JS原型继承:Object.create是否必要?两种原型赋值方式有何差异?
JS原型继承中必须用Object.create吗?两种写法的差异解析
首先明确:原型继承不是必须用Object.create,但Dog.prototype = Animal.prototype和Dog.prototype = Object.create(Animal.prototype)二者有本质差异,前者会引发严重的副作用,后者才是正确的原型继承实现方式。
1. 直接赋值原型对象:Dog.prototype = Animal.prototype
这种写法是让Dog的原型直接指向Animal的原型对象本身,相当于两个构造函数共享同一个原型对象。带来的问题:
- 后续给
Dog.prototype添加/修改方法时,会直接影响Animal.prototype。比如你给Dog.prototype加一个bark方法,所有Animal的实例(比如new Animal('mimi'))也能调用这个方法,完全违背了子类和父类的边界。 - 你代码里设置
Dog.prototype.constructor = Dog时,会直接把Animal.prototype的constructor属性改成Dog,导致new Animal('test').constructor返回的是Dog而不是Animal,破坏了构造函数的原生指向。
2. 使用Object.create:Dog.prototype = Object.create(Animal.prototype)
这种写法会创建一个全新的空对象,这个新对象的内部原型([[Prototype]])指向Animal.prototype,再把这个新对象赋值给Dog.prototype。优势:
Dog的原型和Animal的原型是两个独立的对象,只是新对象继承自Animal的原型。后续给Dog.prototype添加方法,只会影响Dog的实例,不会波及Animal的原型和实例。- 此时设置
Dog.prototype.constructor = Dog,只是修改这个新对象的constructor属性,不会影响Animal.prototype的constructor,保证Animal实例的构造函数指向正确。
结合你的示例代码看问题
你当前的代码运行起来看似正常,但隐藏了隐患:比如你现在打印new Animal('lucy').constructor,会发现它返回的是Dog而不是Animal,这就是直接赋值原型导致的错误。如果换成Object.create的写法,这个问题就会消失。
总结:如果要实现正确的原型链继承,避免父子构造函数的原型污染,推荐使用Object.create,或者直接用ES6的class extends语法(本质还是基于原型链的语法糖)。
内容的提问来源于stack exchange,提问作者Sushmit Sagar
相关产品推荐
相关产品推荐

