[英]JavaScript prototypal inheritance workaround
Here is an example: 这是一个例子:
var Box = function() {
this.id = generateUniqueId();
};
Box.prototype = {
add:function(parent) {
parent.appendChild(this.elm);
}
};
var NewBox = function() {
this.newThing = true;
};
NewBox.prototype = new Box();
NewBox.prototype.remove = function() {
this.elm.parentNode.removeChild(this.elm);
};
var a = new NewBox();
var b = new NewBox();
alert(a.id); // alerts 0
alert(b.id); // also alerts 0! :@
I would like to have a and b (basically each time I create a NewBox
) have their own id
. 我希望a和b(基本上每次创建
NewBox
)都有自己的id
。 I understand that NewBox
is using prototypal inheritance and is thus inheriting from a single instance of the generated id
that it gets from Box
, but I would like it so that each NewBox
gets its own id
without having to explicitly say that inside the NewBox
constructor. 我了解到
NewBox
使用的是原型继承,因此是从Box
生成的id
的单个实例继承的,但是我希望这样做,以便每个NewBox
都有自己的id
而不必在NewBox
构造函数中明确NewBox
。
Maybe it's impossible or I'm doing something really wrong, so please help! 也许这是不可能的,或者我做错了什么,所以请帮助!
Thanks a lot! 非常感谢!
In your example, the Box
constructor gets executed only when you set the NewBox.prototype
object. 在您的示例中,仅当您设置
NewBox.prototype
对象时,才执行Box
构造函数。
You could workaround this by calling the Box
constructor function inside NewBox
with the Function.prototype.apply
method, to set the this
value and forward all the argument values, for example: 您可以通过使用
Function.prototype.apply
方法在NewBox
调用Box
构造函数来解决此问题,以设置this
值并转发所有参数值,例如:
//..
var NewBox = function() {
Box.apply(this, arguments);
this.newThing = true;
};
//..
var a = new NewBox();
var b = new NewBox();
// assuming your `generateUniqueId` function
// increments a number
alert(a.id); // will alert 1
alert(b.id); // will alert 2
Now, each time the NewBox
constructor is called to create a new object instance ( new NewBox();
), it will call the Box
function to apply all its logic on it. 现在,每次调用
NewBox
构造函数创建一个新的对象实例( new NewBox();
)时,它将调用Box
函数在其上应用其所有逻辑。 This will help you to avoid repeating the logic of the parent constructor over and over. 这将帮助您避免一遍又一遍地重复父构造函数的逻辑。
The apply
, is used call the "parent" constructor function setting the this
value to the object instance that is being created by the NewBox
constructor and we pass all arguments provided to this function. 使用
apply
调用“父”构造函数, this
值设置为由NewBox
构造函数创建的对象实例,然后将提供给该函数的所有参数传递给该实例。
Your example also shows a common problem, when you express inheritance relationship through NewBox.prototype = new Box();
当您通过
NewBox.prototype = new Box();
表示继承关系时,您的示例还显示了一个常见问题NewBox.prototype = new Box();
the Box
constructor gets called and it has side effects, this new object will be initialized and your generateUniqueId
function will be executed for the first time, if you want to avoid that, you need to either use a temp constructor, just to make a new object that inherits from Box.prototype
, or use the new ECMAScript 5 Object.create
method for the same purpose, for example: Box
构造函数被调用且具有副作用,此新对象将被初始化,并且您的generateUniqueId
函数将首次执行,如果要避免这种情况,您需要使用temp构造函数,只是为了创建一个新的继承自Box.prototype
对象,或出于相同目的使用新的ECMAScript 5 Object.create
方法,例如:
function inherit(o) {
function Tmp() {}
Tmp.prototype = o;
return new Tmp();
}
//.....
NewBox.prototype = inherit(Box.prototype);
Or: 要么:
NewBox.prototype = Object.create(Box.prototype);
In that way, you express the same inheritance hierarchy without running your Box
constructor that first time, avoiding any side effect that it might cause. 这样,您无需第一次运行
Box
构造函数即可表示相同的继承层次结构,从而避免了可能引起的任何副作用。
At last but not least, whenever you replace a function's prototype property is always recommended to restore the constructor
property of this new prototype object, otherwise it will point to the wrong function. 最后但并非最不重要的一点是,始终建议您每次替换函数的prototype属性时,都要还原此新原型对象的
constructor
属性,否则它将指向错误的函数。
In your example, since you replace the NewBox.prototype
with a new instance of Box
, the NewBox.prototype.constructor
property will point to Box
, (your instances are affected, eg a.constructor === Box; // true
) instead of to NewBox
as you would expect, we need to set it back, eg: 在您的示例中,由于您将
NewBox.prototype
替换为Box
的新实例,因此NewBox.prototype.constructor
属性将指向Box
,(您的实例受到影响,例如a.constructor === Box; // true
)如您NewBox
,将其设置为NewBox
,我们需要将其重新设置,例如:
NewBox.prototype = someObject; // as any of the examples above
NewBox.prototype.constructor = NewBox;
You could abstract those details into a function, as I did in the inherit
function above: 您可以将这些细节抽象为一个函数,就像我在上面的
inherit
函数中所做的那样:
function inherits(child, parent) {
var obj, Tmp = function () {};
Tmp.prototype = parent.prototype;
obj = new Tmp();
child.prototype = obj;
child.prototype.constructor = child;
}
//...
// instead of setting the `NewBox.prototype` manually
inherits(NewBox, Box); // "NewBox inherits from Box"
//...
Maybe it's impossible or I'm doing something really wrong, so please help!
也许这是不可能的,或者我做错了什么,所以请帮助!
You're doing something wrong. 您做错了。
If you want instance-specific values, initialize them in the constructor, not the prototype. 如果需要特定于实例的值,请在构造函数而不是原型中初始化它们。
Matt Ball has the right idea. 马特·鲍尔(Matt Ball)有正确的想法。 Instead try:
而是尝试:
var Box = (function(){
var numberOfBoxes = 0;
function() {
this.id = numberOfBoxes++;
}
})();
Or in the case you want all your (different) classes to have unique ids: 或者,如果您希望所有(不同的)类具有唯一的ID:
var generateUniqueID = (function(){
var runningCount = 0;
return function (){
return runningCount++;
}
})();
var Box = function() {
this.id = generateUniqueId();
};
var NewBox = function() {
this.id = generateUniqueId();
this.newThing = true;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.