2012-05-31 13 views
1

假设我们有这样的构造:anObject.prototype.constructor做什么?

var Foo = function(){ 
    this.x = "y"; 
} 

FooFoo.prototype.constructor计算出相同的功能,但Foo.prototype.constructor = function(){this.x="z"}似乎并没有改变new Foo()结果。但它确实改变了结果

var i = new Foo(); 
i.constructor; // evals to function(){this.x = "z"} 

这是怎么回事?我不打算在上使用这个做任何事情,我只是对语言很好奇。

+0

我不熟悉的说着什么=新功能(){this.x = “Z”} ...是实际有效的语法? – kinakuta

+0

不..这是一个错误。我会解决它。 – AlexMA

+0

有很多相关的问题你可能想要阅读:http://stackoverflow.com/search?q=javascript+constructor+property – 2012-05-31 15:05:36

回答

3

函数的prototype属性的constructor属性意味着指向该函数,以便您可以询问对象是什么构造它的。它是作为创建功能对象的一部分自动设置的(请参阅规范的Section 13.2)。正如你所看到的,如果你愿意,你可以覆盖Foo.prototype上的constructor属性来改变它,但默认情况下就是这样。

有一个很好的理由可以覆盖它,这与继承有关。假设您想要创建一个创建基础对象的构造函数Base,以及创建具有Base的功能以及Derived的添加/修改的派生对象的构造函数。你看,有(无辅助脚本)通常(但在我看来并不理想)的方法是:

function Base() { 
} 
Base.prototype.foo = function() { 
    console.log("I'm Base#foo"); 
}; 

function Derived() { 
} 
Derived.prototype = new Base(); // So we get all the `Base` stuff 
Derived.prototype.bar = function() { 
    console.log("I'm Derived#bar"); 
}; 

var d = new Derived(); 
d.foo(); // "I'm Base#foo" 
d.bar(); // "I'm Derived#bar" 

的问题是,现在,d.constructor === Base而非Derived。因此,能够解决这个问题是很重要的:

... 
Derived.prototype = new Base();   // So we get all the `Base` stuff 
Derived.prototype.constructor = Derived; // Fix up 
... 

(边注:所有这些管道的  —和复杂围绕supercalls   —的是,为什么这么多的人已经创造了这个辅助脚本,包括(咳嗽)mine


注意上面并不意味着是建立继承层次的理想方式。这是你通常看到的,但正如我上面所说的,并不理想。只是为了完整性,这是更好的:

function Base() { 
} 
Base.prototype.foo = function() { 
    console.log("I'm Base#foo"); 
}; 

function Derived() { 
    Base.call(this); // So Base sets up its stuff 
} 
Derived.prototype = Object.create(Base.prototype); // So we get all the `Base` stuff 
Derived.prototype.bar = function() { 
    console.log("I'm Derived#bar"); 
}; 

var d = new Derived(); 
d.foo(); // "I'm Base#foo" 
d.bar(); // "I'm Derived#bar" 

...其中预ES5环境中,您使用的垫片/填充工具为Object.create。但是,我不直接这样做(并且不推荐它),我使用助手脚本,因此它是声明性的和可重复的。

+0

它更清洁使用Derived.prototype = Object.create(Base.prototype)'(With shimmed'Object.create',它们都是一样的),它不会调用可能有'.bind'调用等的构造函数。继承仍然正确建立和instanceof等继续工作。 [MDN]也强调了这一点(https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_Revisited)(尽管他们仍然使用新的A,这很糟糕) – Esailija

+0

@Esailija:的确如此。这基本上就是我的脚本所做的。正如我上面所说的:*“......通常的(虽然不是我脑海中的理想)方式......”可悲的是,人们经常看到这种“通常”的方式。 –

+0

嘿,我甚至没有读到:P'你的脚本'是指血统吗? – Esailija

2

.prototype.constructor只是一个帮手属性,所以创建的对象可以很容易地引用构造函数this.constructor,或者如您的案例i.constructor

随意将其设置到别的东西没有,除了对代码,希望得到一个对象的构造与obj.constructor任何影响:

if(obj.constructor === Foo) { 
//It's a Foo 
} 

所以这是一个好习惯刚刚离开它是。

es5shim依靠.constructor.prototype匀场Object.getPrototypeOf