1

在一些大型项目中看到了这种 JavaScript 模式,它将 ClassA 的属性“复制”或“实现”到 ClassB,但无法弄清楚在传递ClassB 实例作为“this”绑定?

var ClassA = function() {
    //this function is totally empty
};

ClassA.prototype = {
    jump: function() {...some code...},
    dance: function() {
        if (this.canDance) {
            alert("dance");
        }
    }
};

ClassA.implementOn = function(targetClassOrObject) {
    for ( var prop in ClassA.prototype ) {      
        targetClassOrObject[ prop ] = ClassA.prototype[ prop ];
    }
};

var ClassB = function() {
    this.canDance = true;
    ClassA.call(this);          // <------------What's the purpose of this line?
};

ClassA.implementOn(ClassB.prototype);

var instanceOfB = new ClassB();
instanceOfB.dance();
4

4 回答 4

2

如果ClassA构造函数是空的,这没什么大不了的—— callingClassA的空构造函数绝对什么都不做。

但是,当您决定希望ClassA的构造函数为非空时,您会看到该行现在具有非常重要的效果:构造ClassB对象还会在新构造的对象的上下文中调用 - 特定的ClassA构造函数行为ClassB,这如果ClassBClassA.

(当然,JavaScript 没有适当的“子类”,但这显然是在尝试在语言中实现基于类的行为。)

于 2013-02-12T17:19:20.693 回答
1

使用“.call()”在 ClassB 的构造函数中调用 ClassA 的空构造函数的目的

让脚本在ClassA不为空时仍然有效。当然,目前它什么也没做,但将来可能会改变。因此,实现完整的继承模式是一种很好的做法,这样可以更容易地在以后更改代码而不会引入错误。

一旦ClassA更改以实现自定义实例特定属性(在构造函数中设置),您也希望将它们放在ClassB实例上。因此,您也在实例初始化期间调用实例的ClassA构造函数。ClassB

于 2013-02-12T17:18:27.367 回答
1

如果ClassA构造函数是空的(就像在您的示例代码中一样),那么是的,它什么也不做。

但是,您看到这种模式的原因是在它不是的时候。它类似于super基于类的 OO 语言中的调用。

如果您必须在构造函数中做一些工作ClassA以获取处于正确状态的对象,那么您很可能希望在“子类”中做同样的工作。仅仅复制原型的属性可能还不够。

于 2013-02-12T17:19:24.363 回答
0

使用.call,您可以将this被调用方法中的值更改为您指定的参数。 ClassA.call(this)调用ClassA构造函数ClassB作为上下文。这允许您使用ClassBinClassA方法的属性。这些方法都被复制到ClassBvia ClassA.implementOn

您会注意到(new ClassA()).dance()它什么也没做,但会发出(new ClassB()).dance()警报,"dance"因为this.canDance它是真的。

演示:http: //jsfiddle.net/5v7xh/

于 2013-02-12T17:18:10.557 回答