JavaScript中对象的 constructor 属性的介绍

来源:互联网 发布:音乐社美工基本功 编辑:程序博客网 时间:2024/06/01 19:17
作者:傅智威
链接:https://www.zhihu.com/question/19951896/answer/102946428
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


对于instanceof的检测:一般情况下,__proto__和prototype共享指针,给对象赋值实际上改变了它的指针,是它指向了新的对象,而给属性赋值就只是单纯的赋值,共享的指针不受影响。
对于constructor,它只是原型对象的属性,因此在原型对象里把它改了,它自然也就改了。

使用标准方法Object.getPrototypeOf()代替__proto__可以做到不改变实例对象的原型链而访问对象或者添加/修改必要的属性。

————————————————原答案——————————————————

再次更新,正面解答题主的问题。

instanceof 只是检测一个构造函数的原型对象所指向的对象是不是在被检测对象的原型链上。它检测的是一个原型对象是否在原型链上,至于原型对象内容是什么它不管。而在楼主所给的前4个检测例子中,虽然改变了原型对象的某些属性,但是并没有改变原型对象本身(即构造函数的prototype的对象指针),所以检测结果为真,而第五次检测把构造函数的原型对象改变了,所以为假。

换句话说,着其实涉及到怎么理解Javascript的对象,对象的名字只是一个指针,被检测的对象是已经被实例化了的,那么它的原型对象的指针也是确定了的。一般情况它和它的构造函数的原型对象共享一个指针,因此你改变原型对象的属性并不会影响这个指针,而当你改变构造函数的原型对象本身时,这个指针就变了。此时实例对象的原型对象和构造函数的原型对象就没有共用一个指针了,因此当你再用instanceof操作符检测构造函数的原型对象是不是在实例对象的原型链上时,答案就是false了。

至于constructor的理解

更新:修改了一下表述,构造函数的prototype属性被称为构造函数的原型对象。

赞成@贺师俊 的说法,constructor属性是易变的,不可靠的,除非在它变化的时候手动把它绑定回构造函数,否则还是不要用了。

例子1:
//定义构造函数
function P(age){
this.age=age;
}
//给原型添加方法
P.prototype.wel=function(){
console.log(this.age);
};
//实例化一个p对象
var p=new P(21);
//测试对象的方法
p.wel(); //21
// 测试对象的constructor属性
p.constructor;
//function P(age){
this.age=age;
}
这个例子实例对象的constructor属性指向构造函数,是正确的,但是请看下面的例子。
例子2:
//定义构造函数
function P(age){
this.age=age;
}
//给原型添加方法
P.prototype={
wel:function(){
console.log(this.age);
},};
//实例化一个p对象
var p=new P(21);
//测试对象的方法
p.wel(); //21
// 测试对象的constructor属性
p.constructor;
//function Object() { [native code] }

结果看到,虽然例子1和例子2构造函数的功能一样,实例化的对象也有功能一样的方法,但是因为定义构造函数的方式不同,具体是定义构造函数的原型对象的方法不同,例1只单独改变了原型对象某一个属性,而例2整体改变了原型对象,导致实例化之后对象的constructor属性也改变了。

不过用例2这种方法在创建构造函数的情况应该很多,So,constructor这个属性很不可靠。

从上面的例子其实可以看出来,constructor属性并不是实例化的对象的属性,而是构造函数的原型对象的一个属性。
p.hasOwnProperty("constructor"); //false
P.prototype.hasOwnProperty("constructor");//true

对于例2,如果手动给P的prototype.constructor属性赋值P,
P.prototype.constructor=P;
则还是可以用的,但是这就要看个人习惯了。

另外@贺师俊 说“instanceof检测对象的原型链,通常你是无法修改的(不过某些引擎通过私有的__proto__属性暴露出来)。”也不见得,在例1中,不借助非标准的__proto__ 属性,直接用constructor属性就能让p instanceof P结果为假了。
p.constructor.prototype={};
p instanceof P; //fals

至于什么时候会真的这么干我就不太清楚了。
0 0
原创粉丝点击