Javascript:如何正确扩展类

时间:2013-12-12 21:45:08

标签: javascript prototype

通过互联网搜索我总是碰到这种Javascript类扩展方法

function extend(Child, Parent) {
    var F = function() { }
    F.prototype = Parent.prototype
    Child.prototype = new F()
    Child.prototype.constructor = Child
    Child.superclass = Parent.prototype
}

但这与那个有什么不同?

  function extend(Child, Parent) {
    var p = new Parent()
    Child.prototype = p
    Child.prototype.constructor = Child
    Child.superclass = p
  }

这最后一个也很完美。那么我为什么要使用这个额外的var F = function() { }移动呢?

3 个答案:

答案 0 :(得分:7)

直接调用原始构造函数可能会产生不良副作用,如果未传递某些预期参数,则无法正常工作。

这就是他们使用“代理”功能的原因,它允许您获得一个继承自Parent()的新对象,而不实际调用Parent()


这是一个简单的例子:

function Person(name, age) {
    if (name === undefined)
        throw "A name is required";
    this.name = name + "";
    this.age = age;
}

如果Person是父项,那么它会抛出错误,因为没有传递name

答案 1 :(得分:1)

第一个例子是(作为评论中提到的cookie怪物)下面一段代码的垫片,可能更容易理解。:

function extend(Child, Parent) {
  Child.prototype = Object.create(Parent.prototype);
  Child.prototype.constructor = Child;
  Child.superclass = Parent.prototype;
}

基本上,此实现使所有Child实例从(Child.prototype)继承的对象继承自所有Parent实例继承的对象(Parent.prototype)。直观地说,这是JavaScript提供的类继承的最准确表示。

extends的第二个实现是有缺陷的,因为所有Child实例都将从特定的Parent实例继承。如果父实例之间存在显着差异(例如,由于传递给构造函数的参数),Child实例无法准确表示,因为它们都是从通过调用不带参数的Parent构造函数创建的Parent实例继承的。

以下是第一个实现可以执行的操作,第二个实现不能执行的示例:

function Parent(name, age) {
  this.name = name;
  this.age = age;
}
Parent.prototype.greet = function() { return 'I am parent ' + this.name; }

function Child(name){
  Parent.call(this, name, 20); // notice the call to the superclass
}
extend(Child, Parent);
Parent.prototype.greet = function() { return 'I am child ' + this.name + ' and i\'m ' + this.age; }

var c = new Child('Tom');
console.log(c.greet()); // I am child Tom and i'm 20

作为旁注,在Child构造函数中,我调用了Parent构造函数。在处理经典继承时,这实际上很常见,因此这是第一次实现的另一个要点。实际上并不需要,Child构造函数可以安全地忽略调用Parent构造函数,但请记住,该调用基本上确保在创建子实例之前创建的新对象是有效的Parent实例。在我的示例中,如果您不调用Parent构造函数,则不会在Child实例上设置name和age属性,因此greet方法将返回I am child undefined and i'm undefined,远远超出您的预期。

答案 2 :(得分:0)

值得探索在JavaScript中扩展和向对象添加位的不同方法。

使用构造函数     (function(global){         函数SuperClass(){}

    var p = SuperClass.prototype;

    p.doSomething = function() {
        console.log('do something (super)')
    };

    function OtherClass() {
      SuperClass.call(this); 
    }

    OtherClass.prototype = new SuperClass();

    Window.OtherClass = OtherClass;
}(window));

var o = new OtherClass();

使用object.create(无双重实例化) - 并非所有浏览器都支持。

(function (global) {
    // SuperClass - superclass
    function SuperClass() {

    }

    var p = SuperClass.prototype;

    p.doSomething = function() {
        console.log('do something (super)')
    };

    function OtherClass() {
      SuperClass.call(this); 
    }

    OtherClass.prototype = Object.create(SuperClass.prototype);

    Window.OtherClass = OtherClass;
}(window));

功能性混合物: 当您想要将一组通用方法/属性混合到对象中时。

var mixin = function () {
    this.methodA = function () {

    };

    this.methodA = function () {

    };

    return this;
}

var object = function () {
    this.methodB = function () {

    }
}

mixin.call(object.prototype);

所有方法的非常详细的解释:

http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/