5

我正在使用 EaselJS 创建一个游戏,我想知道是否有人可以解释演示文件中使用的继承模式是如何工作的。具体来说,我正在查看以下文件:https ://github.com/CreateJS/EaselJS/blob/master/examples/assets/Ship.js

在第 7 行,Ship 的原型被设置为createjs.container()...

var p = Ship.prototype = new createjs.Container();

然后在第 28 行,存储了对原始构造函数的引用:

p.Container_initialize = p.initialize;  //unique to avoid overiding base class

最后,Ship对象在第 30 行初始化

p.initialize = function () {
    this.Container_initialize();

我正试图围绕这种模式展开思考,因为它与我过去遇到的任何事情都不一样。有人可以向我解释为什么你想使用一个类的实例作为新类的原型吗?也许只是给我指出一个解释这种模式的链接?非常感谢这里的任何帮助......我意识到这个问题有点含糊。

4

1 回答 1

8

我正试图围绕这种模式展开思考,因为它与我过去遇到的任何事情都不一样。

我也不。它并没有太大的魔力,但他的结构绝对不常见。有关正确的模式,请参阅正确的 javascript 继承

有人可以向我解释为什么你想使用一个类的实例作为新类的原型吗?

你没有。您想使用从父类的原型对象继承的对象。不幸的是,很多人都使用new ParConstructor——如果构造函数为空,它会很好地工作。如果构造函数确实创建了实例属性或有其他副作用,则可能会引起麻烦。不过,大多数人似乎并没有注意到或关心这一点。

这种模式的解释?

function Ship() {
    this.initialize();
}

这只是调用initialize新实例上的方法(this在构造函数中)。我没有看到将初始化代码直接放在构造函数中的任何好处,但尽管如此。

var p = Ship.prototype = new createjs.Container();

如上所述,这是设置原型链以从Container“类”继承方法。它可能会进行不必要的实例初始化,因此应将其替换为Object.create调用。它为原型创建了一个快捷变量。

// constructor:
p.Container_initialize = p.initialize;    //unique to avoid overiding base class

在这里,创建了对父构造函数的显式引用。initialize属性 onp是从原型继承Container,现在它是对象的一个​​自己的属性,p具有描述性名称。这是必要的,因为……</p>

p.initialize = function () {
    this.Container_initialize();
    … // property init stuff

…这里initialize在原型对象上声明了一个自己的方法,隐藏了继承的方法。尽管如此,现在可以使用该专用属性在当前实例上调用“超级”初始化代码。这样做是 常见的,但不是以这种方式与方法。相反,call通常用于在子实例上应用父构造函数。

更好(至少,更熟悉):

function Ship() {
    this.initialize();
}

var super_p = createjs.Container.prototype,
    p = Ship.prototype = Object.create(super_p);

p.initialize = function() {
    super_p.initialize.call(this);
    … // property init stuff

或者,或者没有initialize

function Ship() {
    createjs.Container.call(this);
    … // property init stuff
}
Ship.prototype = Object.create(createjs.Container.prototype);
于 2013-08-22T16:02:20.807 回答