关于new与Object.create的原型继承差异:为何cat无法调用eat方法?
首先得纠正你一个认知:new Animal()并不完全等同于Object.create(Animal.prototype),后者只是new操作的第一步,完整的new过程还包含调用构造函数这关键一步,这就是问题的核心。
先看const dog = new Animal()的执行逻辑
当你用new调用构造函数时,JS会做三件事:
- 创建一个空对象,让这个对象的
[[Prototype]](原型)指向Animal.prototype - 调用
Animal构造函数,把构造函数里的this绑定到这个新创建的空对象上 - 如果构造函数没有返回自定义对象,就把这个新对象作为返回值(也就是这里的
dog)
所以Animal构造函数里的this.eat = function() {...},其实是直接给dog这个对象本身添加了一个自有属性eat,根本不是从原型继承来的——你调用dog.eat()时,找的是它自己身上的方法,自然能正常执行。
再看两种cat的情况
1. const cat = Object.create(Animal)
这里你把Animal这个构造函数本身当作了原型,所以cat的原型链是:cat → Animal函数 → Function.prototype → Object.prototype。整个链条里都没有eat方法,所以调用cat.eat()自然会报错“不是函数”。
2. const cat = Object.create(Animal.prototype)
这种方式确实创建了一个原型指向Animal.prototype的对象,但它没有触发Animal构造函数的执行。你的eat方法是写在构造函数内部、通过this赋值给实例的,而Animal.prototype本身并没有eat这个属性——所以cat的原型链里找不到eat,调用时同样报错。
为什么把eat放到Animal.prototype上就可以?
当你把eat直接赋值给Animal.prototype.eat时,Animal.prototype上就有了这个方法。此时用Object.create(Animal.prototype)创建的cat,它的原型指向Animal.prototype,当调用cat.eat()时,JS会沿着原型链找,在Animal.prototype上找到eat方法,自然就能正常执行了。
总结一下:
- 构造函数内部通过
this添加的属性/方法,是实例的自有属性,只有在调用构造函数时才会被添加到实例上 Object.create()只是创建一个指定原型的空对象,不会自动调用构造函数new关键字的核心是:创建原型关联的对象 + 调用构造函数初始化实例属性
内容的提问来源于stack exchange,提问作者chuchomp

