JavaScript中修改原型链会对constructor属性产生影响吗?
嘿,这个问题问得太戳痛点了!我当初刚啃原型链这块的时候,就因为没搞懂这个踩过好几个小坑,今天就跟你掰开揉碎了说清楚~
首先得先唠唠constructor属性到底是啥:咱们定义一个构造函数的时候,它的prototype对象默认自带一个constructor属性,这个属性会直接指向构造函数本身。比如你写个function Person() {},那Person.prototype.constructor就等于Person,用new Person()创建的实例,顺着原型链找constructor,也会找到Person。
那如果修改了原型链呢?这情况可就变了!最常见的场景就是直接替换整个原型对象,比如:
// 先定义个基础构造函数 function Person(name) { this.name = name; } // 原来的原型上有默认的constructor console.log(Person.prototype.constructor); // 输出:[Function: Person] // 直接把原型换成一个全新的对象 Person.prototype = { sayHello: function() { console.log(`嘿,我是${this.name}`); } } const me = new Person("小李"); console.log(me.constructor); // 你猜输出啥?是[Function: Object]!
为啥会这样?因为咱们新替换的这个原型对象是个普通的空对象(除了我们加的sayHello方法),它本身没有constructor属性。那实例me找constructor的时候,就会顺着原型链往上爬,最后爬到Object.prototype,而Object.prototype.constructor指向的是Object,所以就输出这个啦。
那要是想避免这种“跑偏”的情况怎么办?很简单,在替换原型对象的时候,手动把constructor属性加回去,指回原来的构造函数就行:
Person.prototype = { constructor: Person, // 手动指定回Person sayHello: function() { console.log(`嘿,我是${this.name}`); } } const you = new Person("小王"); console.log(you.constructor); // 这下就正常输出[Function: Person]了
还有一种修改原型链的方式,比如用Object.setPrototypeOf()修改某个实例的原型指向,这时候constructor也会跟着变。举个例子:
function Animal(type) { this.type = type; } const dog = new Animal("小狗"); console.log(dog.constructor); // 输出[Function: Animal] // 把dog的原型换成Person的原型 Object.setPrototypeOf(dog, Person.prototype); console.log(dog.constructor); // 这时候就输出[Function: Person]了
这是因为dog现在的原型链顶端变成了Person.prototype,而我们刚才给Person.prototype加了正确的constructor,所以它就指向Person了。
总结一下哈:修改原型链确实会影响constructor属性,因为constructor是依附在原型链上的属性,你改了原型链的路径,实例找constructor的“路线”就变了。如果替换原型的时候没手动设置constructor,很容易出现它指向Object的情况,这时候就会跟你预期的不一样啦。
内容来源于stack exchange

