对象constructor属性疑问:为何new Rabbit()实例的constructor指向Animal?
为什么
r.constructor指向Animal而不是Rabbit? 嘿,这个问题绝对是JS原型链入门时最容易踩的坑之一,我来给你拆解明白~
先看你贴的核心代码:
function Animal(){ this.name = 'Animal' } var animal1 = new Animal(); function Rabbit(){ this.canEat = true; } Rabbit.prototype = new Animal(); // 这行是关键转折点 var r = new Rabbit(); console.log(r.constructor) // 输出Animal
问题出在哪?
默认情况下,每个函数的prototype对象里都自带一个constructor属性,这个属性默认指向函数本身。比如一开始Rabbit.prototype.constructor是指向Rabbit的。
但当你执行Rabbit.prototype = new Animal()时,你把Rabbit原来的原型对象整个替换成了Animal的实例。而这个Animal实例的原型链是:animal实例 -> Animal.prototype,Animal.prototype.constructor默认是Animal。
当你访问r.constructor时,JS会顺着原型链往上找:
- 先看
r自身有没有constructor?没有,因为你没在Rabbit里定义它。 - 然后找
r.__proto__(也就是Rabbit.prototype,现在是Animal的实例),这个实例自身也没有constructor。 - 继续往上找
Animal.prototype,这里的constructor指向Animal,所以最终返回的就是Animal。
为什么赋值prototype前调用Rabbit就正常?
如果你先创建r,再替换Rabbit.prototype:
var r = new Rabbit(); // 先创建实例 Rabbit.prototype = new Animal(); // 再替换原型 console.log(r.constructor) // 输出Rabbit
这是因为实例的原型指向是在new的时候就固定下来的。r的__proto__指向的是Rabbit原来的原型对象(那个自带constructor: Rabbit的对象),之后你修改Rabbit.prototype并不会影响已经创建好的r的原型链。
怎么解决这个问题?
很简单,替换完Rabbit.prototype之后,手动把constructor指回Rabbit就行:
function Animal(){ this.name = 'Animal' } function Rabbit(){ this.canEat = true; } Rabbit.prototype = new Animal(); Rabbit.prototype.constructor = Rabbit; // 手动修正constructor指向 var r = new Rabbit(); console.log(r.constructor) // 现在输出Rabbit啦!
这样r顺着原型链找constructor时,会先找到Rabbit.prototype上的constructor,也就是Rabbit,就符合你的预期了。
内容的提问来源于stack exchange,提问作者Mayank
相关产品推荐
相关产品推荐

