在构造函数上设置原型时,instanceof
运算符仅返回true
,直到原型发生变化。为什么呢?
function SomeConstructorFunction() {
}
function extendAndInstantiate(constructorFn) {
constructorFn.prototype = {}; //Can be any prototype
return new constructorFn();
}
var child1 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //true
var child2 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //false
console.log(child2 instanceof SomeConstructorFunction); //true
答案 0 :(得分:3)
constructorFn.prototype = {}; //Can be any prototype
不正确!
constructorFn.prototype = Object.prototype;
或者任何其他原生原型都会使它们都成立。
原因是您第一次调用extendAndInstantiate()
时,您将SomeConstructorFunction的原型设置为某个(此处为空对象{}
)。对于child1
,instanceOf将仅返回true,而SomeConstructorFunction的原型是{}
的确切实例。当您再次运行extendAnInstantiate()
时,您将SomeConstructorFunction
的原型更改为{}
的其他实例,因此child2
将成为instanceOf新的{}
,但child1
仍然是旧{}
的实例,因此child1
将返回false,而child2
将返回true。如果您将原型设置为常见原型(例如Object.prototype
或Array.prototype
),则它将始终返回true。
另一种说明方法是将{}
拉出函数,并将其分配给变量obj
。
var obj = {};
function extendAndInstantiate(constructorFn) {
constructorFn.prototype = obj;
return new constructorFn();
}
现在这将永远返回true,因为每次运行该函数时都不会创建新的{}
。
答案 1 :(得分:3)
原型继承可能有点大脑弯曲。我已经在下面的答案中为原型继承写了一个简单的解释,我建议你阅读它:https://stackoverflow.com/a/8096017/783743
现在回答你的问题。考虑以下功能:
function F() {}
我可以使用F
创建new
的实例,如下所示:
var f = new F;
按预期f instanceof F
返回true
。这是因为instanceof
运算符会在F.prototype
的原型链中检查f
,如果存在,则返回true
。请参阅我上面链接的答案。
现在说我创建了一个新功能G
,如下所示,并将F.prototype
设置为G.prototype
:
function G() {}
F.prototype = G.prototype;
如果我现在再次评估f instanceof F
,则返回false
。这是因为F.prototype
不再位于f
的原型链中(请记住F.prototype
现在是G.prototype
)。
现在让我们创建一个F
的新实例:
var g = new F;
如果您评估g instanceof G
,即使true
,它也会返回g = new F
。这是因为G.prototype
原型链中存在g
。
这不是错误。这是JavaScript的工作方式。事实上,我们可以利用此功能创建一些非常有趣的功能:Instantiate JavaScript functions with custom prototypes
答案 2 :(得分:0)
instanceof
基于原型对象。
function extendAndInstantiate(constructorFn) {
constructorFn.prototype = {}; //Can be any prototype
...
当您将原型设置为{}时,您将创建一个新对象并将其设置为原型。因为它与原型不是同一个对象,instanceof
返回false。
这样的设置对于所有情况都将返回true,因为原型将是同一个对象:
function SomeConstructorFunction() {
}
var emptyObj = {};
function extendAndInstantiate(constructorFn) {
constructorFn.prototype = emptyObj;
return new constructorFn();
}
var child1 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //true
var child2 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //true
console.log(child2 instanceof SomeConstructorFunction); //true
答案 3 :(得分:0)
每次拨打extendAndInstantiate
时,都会使用{}
创建一个新对象,并将其指定为SomeConstructorFunction
的原型。这将清除现有实例与SomeConstructorFunction
之间的链接。因此,只有最后一个将是SomeConstructorFunction
的有效实例。
function SomeConstructorFunction() {
}
function extendAndInstantiate(constructorFn) {
constructorFn.prototype = {}; //New instance as prototype
return new constructorFn();
}
var child1 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //true
var child2 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //false
console.log(child2 instanceof SomeConstructorFunction); //true
var child3 = extendAndInstantiate(SomeConstructorFunction);
console.log(child1 instanceof SomeConstructorFunction); //false
console.log(child2 instanceof SomeConstructorFunction); //false
console.log(child3 instanceof SomeConstructorFunction); //true
因此,您可以按照@ ben336显示的方法或在分配原型之前进行条件检查,如下所示。
function Base(){
}
function SomeConstructorFunction() {
}
function extendAndInstantiate(constructorFn, Base) {
if(!(constructorFn.prototype instanceof Base)){
console.log(" extend only once ");
constructorFn.prototype = new Base();
}
return new constructorFn();
}
var child1 = extendAndInstantiate(SomeConstructorFunction, Base);
console.log(child1 instanceof SomeConstructorFunction); //true
var child2 = extendAndInstantiate(SomeConstructorFunction, Base);
console.log(child1 instanceof SomeConstructorFunction); //true
console.log(child2 instanceof SomeConstructorFunction); //true
var child3 = extendAndInstantiate(SomeConstructorFunction, Base);
console.log(child1 instanceof SomeConstructorFunction); //true
console.log(child2 instanceof SomeConstructorFunction); //true
console.log(child3 instanceof SomeConstructorFunction); //true