我无法理解javascript的这种循环行为。
有人可以告诉我为什么这样设计? 这种行为有没有真正的用例?
为什么这个循环? { 新创建的实例从构造函数对象的prototype属性继承属性。 构造函数的prototype属性是一个保持构造函数属性的对象。 构造函数属性等于构造函数对象。 构造函数对象再次保留原型属性。 }
instance1 --- inhertis(keep) - > func()的原型属性 - >保持构造函数属性 - >函数对象func - >保持原型属性。
var func = function(){};
var construct = func.prototype.constructor;
console.log(construct === func); //true
var instance1 = new func();
更新:即使在我指定的其他内容之间,instanceof也总是返回true。
var func1 = function(){};
func1.prototype.constructor = 1;
var instance1 = new func1();
console.log(instance1 instanceof func1); //true
var func2 = function(){};
func2.prototype.constructor = 0;
var instance2 = new func2();
console.log(instance2 instanceof func2); //true
很抱歉在1中提出2个问题,但两者可能都有关系。
答案 0 :(得分:5)
当然它保留了实例。为什么不呢?如果你正在制作一只鸭子,它就是一只鸭子 - 它的DNA就说它是一只鸭子,无论你把它画成黑色还是教它成为一只鹅。
此外,在您的情况下,设置构造函数无效。当您执行new func
(或new func()
,它们是相同的)时,您将获取该函数的内部属性([[Construct]]
属性),而不是func.prototype.constructor
。< / p>
每个对象都定义了
obj.constructor
,因为它是在每个“构造函数”上定义的:即Object Number Function Date Boolean String
等等。每个原型中都有constructor
属性:
Object.prototype.constructor === Object;
String.prototype.constructor === String;
//etc
每个人都有prototype.constructor
指向自己。
由于函数也可以像构造函数一样运行,因此它们的.prototype.constructor
属性也指向它们自己。 AFAIK,在语言本身中没用。
简洁,技术性的答案? http://es5.github.com/#x11.8.6
//foo instanceof bar
Return the result of calling the [[HasInstance]] internal method of bar with argument foo.
(稍微转述)
基本上,你问的是母鸭:“对不起,女士,这是你的孩子吗?”孩子对此事几乎没有发言权。
编辑:如评论中所述,更改原型确实会影响instanceof
结果。如上所述,有直观的答案和技术答案。
直观的答案很简单:原型定义了对象。因此,改变原型可以改变DNA - 你可以将鸭子变成鹅,而不是将它教成鹅,而是通过转向DNA并将其变成鹅DNA。
技术性正在看[[HasInstance]]
的作用。 (other [[HasIntsance]]
调用这个)规范真的很干,很简洁,所以这里的算法用伪javascript编写:
//assume Func is the function we're talking about
function HasInstance ( value ) {
if ( IsntAnObject(value) ) {
return false;
}
var proto = Func.prototype;
if ( Type(proto) !== "Object" ) {
return false;
}
while ( value !== null ) {
value = value.prototype;
if ( value === proto ) {
return true;
}
}
return false;
}
可以看出,通过更改原型,我们正在改变行为 - value
将是不同的值。
答案 1 :(得分:2)
非常好的问题!
由于原型是Object
个实例(就像JavaScript中的所有内容一样),因此他们必须共享Object
的原型。这恰好有constructor
属性。
实例共享其构造函数原型的所有属性,包括constructor
属性。
指定函数原型的constructor
属性以反映函数本身。例如:
Object.prototype.constructor === Object
Function.prototype.constructor === Function
/* the same with every other function */
当你覆盖构造函数的原型时,就像这样:
Func.prototype = 1
原型本身和Func
的所有实例都有不同的constructor
属性,在上面的例子中是Number
。
对于instanceof
,它与constructor
属性本身无关。它与prototype
。
function Func() {}
Func.prototype = { a: 1 } // assign a prototype
var fn = new Func() // create an instance
fn instanceof Func // true (reflects connexion to the original prototype)
Func.prototype = { b: 2 } // assign a completely different prototype
fn instanceof Func // false (the connexion is broken)
答案 2 :(得分:0)
下面的小代码可能会让您感到困惑。正如您所看到的,新实例实际上没有名为“constructor”的属性。因此,当您要求instance.constructor
时,由于原型链接,您实际上获得了instance.prototype.constructor
值。为了保持一致,您希望instance.constructor
设置为与创建它的函数相同的值。这就是JS解释器将prototype.constructor
设置为函数本身的值的原因。
function Rabbit() { }
var rabbit = new Rabbit()
alert( rabbit.hasOwnProperty('constructor') ) // false
alert( Rabbit.prototype.hasOwnProperty('constructor') ) // true
这适用于非功能对象。它们没有自己的.constructor属性,因此调用最终会在Object.prototype.constructor
中结束,因此您可以获得所有非函数对象的相同答案。
此时要问的问题是为什么JS设计者为函数对象做出了这个选择,而不是显式设置实例的constructor
属性来自行运行。我不知道答案,但我可以猜测它在语言中增加了更多的“活力”。即使您没有创建实例的原始函数,instance.constructor也可用于以通用方式创建新实例。
function makeUnicorn(animal) {
var unicorn = new animal.constructor();
unicorn.HornOnNose = true;
return unicorn;
}
var unicornRabbit = makeUnicorn(rabbit);
请注意,上面运行的任何对象都没有错误,即使是不是函数实例的对象。您可以设想使用此JavaScript功能来自定义上述“通用”函数的行为,如果构造函数是实例的自有属性,则无法使用该函数。
Horse.prototype.constructor = function() {
var newHorse = new Horse();
newHorse.Color = "White";
return newHorse;
}