javascript实例对象的constructor属性值是怎么来的?

2013-07-11 17:57:02 +08:00
 pythonee
疑惑来源于我做的一个实验,实验过程如下:

> function Foo(){};
> var f1 = new Foo();
> f1.constructor

这里能按期待的输出,也就是 Foo() 函数本身,但是如果我更改Foo.prototype属性,就有点奇怪了

> Foo.prototype = {};
> var f2 = new Foo();
> f2.constructor

这时候输出

function Object() { [ native code] }

我就开始猜想,
instance.constuctor === instance.__proto__.constructor

接着实验,把构造器的prototype指到Function()实例,看看什么情况
> Foo.prototype = new Function();
> var f3 = new Foo();
> f3.constructor

这时候按猜想,f3.__proto__ == Foo.prototype 也即 new Function(); 而
new Function().constructor就是function Function() { [ native code] },实际输出和猜想吻合。


再来点极端的,如果instance.__proto__ = null, 是个什么情况?

> f3.__proto__ = null;

这时候f3不再具备constructor属性!! 而typeof(f3)还是object,可是一个object既然没有constructor!!看起来猜想是正确的,但是这些是为什么呢?希望各位大牛指点,或者我的思路有什么问题没有?
3450 次点击
所在节点    程序员
11 条回复
switch
2013-07-11 19:12:15 +08:00
可以查看 ECMAScript 5,裡面定義了 typeof 是如果返回值的。
guchengf
2013-07-11 19:54:32 +08:00
pythonee
2013-07-11 22:02:57 +08:00
@guchengf

有点乱了,实例的constructor也可以乱改,但是instanceof却是用最初创建它的来判断真假,这里谁记录最初创建它的构造器的呢?这样的话 instance.constructor也未必等于instance.__proto__.constructor,不过如果你不改的话,两者却是相等的,文档第一句话也确实这么说

Returns a reference to the Object function that created the instance's prototype.
otakustay
2013-07-11 23:19:52 +08:00
一个函数建立的时候,就有.prototype.constructor指向函数本身
你改了prototype,新的prototype上没有constructor,因此f2.constructor在f2上没有,在Foo.prototype上也没有,就会再向上找Object.prototype上,在好运边能找到,因此就是Object这个东西
pythonee
2013-07-12 09:54:45 +08:00
@otakustay 你说的原因和我想的一样,但是结果却不一样,函数建立的时候
确实是
function == function.prototype.constructor,而这时候由这个function创建的instance有以下关系
instance.constructor == instance.__proto__.constructor
又有
instance.__proto__ == function.prototype
所以
instance.constructor == function.prototype.constructor
如果我修改function.prototype,比如上面的f2,即Foo.prototype = {};所以
f2.constructor = {}.constructor,
而{}.constructor == Object.prototype.constructor,也即是Object(){ [native code]}
而这后面的结果你的顺藤摸瓜式想法不一样啊
otakustay
2013-07-12 10:00:48 +08:00
@pythonee 我们的结果是一样的啊,最后都是追溯到Object.prototype.constructor,即Object本身,Object本身就是Object() { [native code] }

原型链的查找用一句话概括,就是“自己没有找自己原型,原型没有找原型的原型”,因此过程是

f2.constructor(没有) -> f2.__proto__(就是Foo.prototype).constructor(没有) -> f2.__proto__.__proto__(就是Object.prototype).constructor(有) -> Object
pythonee
2013-07-12 10:01:06 +08:00
@otakustay 而且我试验了,发现并没有顺着原型链来找构造函数这个说法啊
otakustay
2013-07-12 10:51:45 +08:00
@pythonee constructor就是一个普通的属性,任何属性都是通过原型链来找的,没有例外,不是很理解你是怎么得了“没有顺着原型链”这个结论的……
pythonee
2013-07-12 11:37:46 +08:00
@otakustay

我的求值过程是代入,而不是顺着原型链,

f2.constructor(有) == f2.__proto__(就是Foo.prototype).constructor(有) == {}.constructor(有) == Object.prototype.constructor == Object(){[native code]}

我认为constructor是特殊的属性,而不是普通的
otakustay
2013-07-12 11:43:40 +08:00
@pythonee
是这样的,f2.__proto__.constructor === {}.constructor,但是{}.constructor是怎么来的呢?{}本身没有constructor(这个是肯定的,你用({}).hasOwnProperty('constructor')试),所以是({}).__proto__.constructor,也就是Object.prototype.constructor,所以还是顺着上去的

所谓“有”还是“没有”,是用.hasOwnProperty('constructor')来检测的,因此在每一级试下这个方法就行了

一种证明他是“顺着找”的方法是

var f2 = new Foo();
console.log(f2.constructor); // function Object() { [native code] }
Object.prototype.constructor = 'fuck';
console.log(f2.constructor); // 'fuck'
pythonee
2013-07-12 13:33:47 +08:00
@otakustay

如果这样定义"有"和"没有"的话,那从一开始f2.contructor就是没有的,可是如果按contructor的定义出发的我,是有的,所以,我觉得我们的分歧点在这里,不过我也能接受你的观点

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/75477

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX