Javascript - 为什么这个循环? instance->(prototype property-> constructor property-> function object-> constructor property)

时间:2011-11-27 12:34:32

标签: javascript

我无法理解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个问题,但两者可能都有关系。

3 个答案:

答案 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;
}