具有原型和基类的JS OO模式

时间:2012-12-11 11:47:27

标签: javascript

对于OO JS来说这是一个很好的模式吗? 我正在寻找的是一种解决JavaScript继承的简单方法。

function MySuperClass(arg)
{
    this.arg1 = arg;
}
function MyBaseClass(arg)
{
    this.base = MySuperClass;
    this.base(arg);
    this.arg2 = arg;
}
MyBaseClass.prototype = new MySuperClass();
function MySpecificClass(arg)
{ 
    this.base = MyBaseClass;
    this.base(arg);
    this.arg3 = arg;
}
//ensures inheritance of all properties
MySpecificClass.prototype = new MyBaseClass();

var myFirstInstance = new MySpecificClass("test");
var mySecondInstance = new MySpecificClass("test2");

2 个答案:

答案 0 :(得分:3)

注意:请参阅ES2015更新的结尾。

ES5及更早版本

那里有几个问题。

  1. 您的MySuperClass函数需要一个参数,但是当您调用它来创建MyBaseClass.prototype时,您无法给它一个。

  2. 您在实例上设置的base属性无法正常使用MyBaseClass中的代码,因为MyBaseClass期望MySuperClassMySpecificClass ,但事实并非如此,因为MySuperClass已覆盖它。

  3. 这很复杂。你非常聪明,确定要做三代(MyBaseClassMySpecificClassParent),因为对于两级层次结构来说这很容易做到,但对于三个+等级,它要复杂得多。 : - )

    如果你想在JavaScript中彻底讨论处理继承,调用超类方法等,我written an article on itwritten a toolkit就可以了。阅读文章并查看工具包源代码(超出了本文)可能有助于理解原型链的工作原理以及如何使用工作

    这是一个使用任何工具包的的示例,而不是试图使超级调用变得容易。为了清楚起见,我在三代中使用了ChildGrandChild// A parent (base) "class" function Parent(a) { this.a = a; } Parent.prototype.one = function() { console.log("I'm Parent#one: a = " + this.a); }; Parent.prototype.two = function() { console.log("I'm Parent#two: a = " + this.a); }; // A child "subclass" function Child(a, b) { // Chain to "superclass" constructor Parent.call(this, a); // Do our own init this.b = b; } // Create the prototype objct that `new Child` will assign to instances // by creating a blank object backed by `Parent.prototype`. Also set // the `constructor` property on the object; JavaScript defines that it // will refer back to the function on the default prototype objects, so // we do that for consistency despite nothing in JavaScript actually // _using_ `constructor`. Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; // Add things to `Child.prototype` Child.prototype.one = function() { Parent.prototype.one.call(this); console.log("I'm Child#one: b = " + this.b); }; Child.prototype.three = function() { console.log("I'm Child#three: b = " + this.b); }; // A grandchild "subclass" function GrandChild(b, c) { // Chain to "superclass" constructor // Note that GrandChild has a fixed value for Parent's `a` Child.call(this, "GrandChildFixedA", b); // Do our own init this.c = c; } // Again create a blank object to be the prototype `new GrandChild` // assigns, again set `constructor` GrandChild.prototype = Object.create(Child.prototype); GrandChild.prototype.constructor = GrandChild; // Add things to it GrandChild.prototype.one = function() { Child.prototype.one.call(this); console.log("I'm GrandChild#one: c = " + this.c); }; GrandChild.prototype.three = function() { Child.prototype.three.call(this); console.log("I'm GrandChild#three: c = " + this.c); }; 这两个词:

    var p = new Parent("ParentA");
    console.log("Calling p.one");
    p.one();    // "I'm Parent#one: a = ParentA"
    console.log("Calling p.two");
    p.two();    // "I'm Parent#two: a = ParentA"
    var c = new Child("ChildA", "ChildB");
    console.log("Calling c.one");
    c.one();    // "I'm Parent#one: a = ChildA" then "I'm Child #one: b = ChildB"
    console.log("Calling c.two");
    c.two();    // "I'm Parent#two: a = ChildA"
    console.log("Calling c.three");
    c.three();  // "I'm Child#three: b = ChildB"
    var gc = new GrandChild("GrandChildB", "GrandChildC");
    console.log("Calling gc.one");
    gc.one();   // "I'm Parent#one: a = GrandChildFixedA" then "I'm Child #one: b = GrandChildB" then "I'm GrandChild#one: c = GrandChildC"
    console.log("Calling gc.two");
    gc.two();   // "I'm Parent#two: a = GrandChildA"
    console.log("Calling gc.three");
    gc.three(); // "I'm Child#three: b = GrandChildB" then "I'm GrandChild#three: c = GrandChildC"
    

    用法:

    // Some things that should be true
    console.log("p instanceof Parent? " + (p instanceof Parent));
    console.log("c instanceof Parent? " + (c instanceof Parent));
    console.log("c instanceof Child? "  + (c instanceof Child));
    console.log("gc instanceof Parent? " + (gc instanceof Parent));
    console.log("gc instanceof Child? "  + (gc instanceof Child));
    console.log("gc instanceof GrandChild? "  + (gc instanceof GrandChild));
    
    // And some things that *shouldn't* be true:
    console.log("p instanceof Child? (should be false) " + (p instanceof Child));
    console.log("p instanceof GrandChild? (should be false) " + (p instanceof GrandChild));
    console.log("c instanceof GrandChild? (should be false) " + (c instanceof GrandChild));
    

    测试instanceof,虽然如果你正在使用很多实例,你可能想要阅读鸭子类型:

    Object.create

    如果您不在启用ES5的环境中,可以将此垫片用于Object.create = function(p) { var o; function ctor() { } ctor.prototype = p; o = new ctor(); ctor.prototype = null; return o; }; (注意:一个完整的垫片,足以启用上述内容):< / p>

    // A parent (base) "class"
    var Parent = Lineage.define(function(p) {
      p.initialize = function(a) {
        this.a = a;
      };
      p.one = function() {
        console.log("I'm Parent#one: a = " + this.a);
      };
      p.two = function() {
        console.log("I'm Parent#two: a = " + this.a);
      };
    });
    
    // A child "subclass"
    var Child = Lineage.define(Parent, function(p, pp) {
      p.initialize = function(a, b) {
        // Chain to "superclass" constructor
        pp.initialize.call(this, a);
    
        // Do our own init
        this.b = b;
      };
      p.one = function() {
        pp.one.call(this);
        console.log("I'm Child#one: b = " + this.b);
      };
      p.three = function() {
        console.log("I'm Child#three: b = " + this.b);
      };
    });
    
    // A grandchild "subclass"
    var GrandChild = Lineage.define(Child, function(p, pp) {
      p.initialize = function(b, c) {
        // Chain to "superclass" constructor
        // Note that GrandChild has a fixed value for Parent's `a`
        pp.initialize.call(this, "GrandChildFixedA", b);
    
        // Do our own init
        this.c = c;
      };
      p.one = function() {
          pp.one.call(this);
          console.log("I'm GrandChild#one: c = " + this.c);
      };
      p.three = function() {
          pp.three.call(this);
          console.log("I'm GrandChild#three: c = " + this.c);
      };
    });
    

    您可以看到为什么工具包脚本会让生活变得更轻松。你有几个可供选择。以下是使用Lineage,我的工具包:

    的上述内容
    class

    用法是一样的。

    ES2015及更高版本

    从ES2015(又名“ES6”)开始,JavaScript获得了superclass Parent { constructor(a) { this.a = a; } one() { console.log("I'm Parent#one: a = " + this.a); } two() { console.log("I'm Parent#two: a = " + this.a); } } class Child extends Parent { constructor(a) { super(a); } one() { super.one(); console.log("I'm Child#one: a = " + this.a); } three() { console.log("I'm Child#three: a = " + this.a); } } class GrandChild extends Child { constructor(a) { super(a); } one() { super.one(); console.log("I'm GrandChild#one: a = " + this.a); } three() { super.three(); console.log("I'm GrandChild#three: a = " + this.a); } } // Usage var p = new Parent("ParentA"); console.log("Calling p.one"); p.one(); // "I'm Parent#one: a = ParentA" console.log("Calling p.two"); p.two(); // "I'm Parent#two: a = ParentA" var c = new Child("ChildA", "ChildB"); console.log("Calling c.one"); c.one(); // "I'm Parent#one: a = ChildA" then "I'm Child #one: b = ChildB" console.log("Calling c.two"); c.two(); // "I'm Parent#two: a = ChildA" console.log("Calling c.three"); c.three(); // "I'm Child#three: b = ChildB" var gc = new GrandChild("GrandChildB", "GrandChildC"); console.log("Calling gc.one"); gc.one(); // "I'm Parent#one: a = GrandChildFixedA" then "I'm Child #one: b = GrandChildB" then "I'm GrandChild#one: c = GrandChildC" console.log("Calling gc.two"); gc.two(); // "I'm Parent#two: a = GrandChildA" console.log("Calling gc.three"); gc.three(); // "I'm Child#three: b = GrandChildB" then "I'm GrandChild#three: c = GrandChildC" 关键字,这大大简化了上述内容,并且可以在今天中使用进行转换。

    {{1}}

答案 1 :(得分:0)

我正在使用这种方法:

var func1 = function(parameter1, parameter2) {
    // do your stuff here
}

var func2 = function(parameter1, parameter2, parameter3) {
    // call the constructor of func1 with actual 'this'
    func1.call(this, parameter1, parameter2);

    // do your specific task here
}

func2.prototype = func1.prototype;
func2.prototype.constructor = func2;

工作正常:)