手写原型继承是否正确?class语法糖与该实现是否完全等效?
关于你的原型继承实现问题
首先先把你没写完的代码补全(应该是Lion.prototype = Object.create(Animal.prototype)),咱们一步步拆解你的问题:
1. 你的手写原型继承是否正确?
大方向是对的,但有个关键遗漏:没有修正Lion.prototype.constructor的指向。
完整的正确实现应该是这样:
let Animal = function () { this.eats = true; } Animal.prototype.run = function () { console.log("Running"); } let Lion = function () { Animal.call(this); // 调用基类构造函数,给实例添加专属属性 this.roar = function () { console.log("Roaring"); } } // 搭建原型链,让Lion继承Animal的原型方法 Lion.prototype = Object.create(Animal.prototype); // 修正constructor指向——否则Lion.prototype.constructor会指向Animal,不符合语义 Lion.prototype.constructor = Lion;
如果不修正constructor,用new Lion()创建的实例,它的constructor属性会指向Animal,虽然instanceof判断不会完全失效,但从语义和后续扩展角度来说,这是不严谨的。
2. 该实现是否共享了基类的属性与方法?
分两种情况来看:
- 原型上的方法(比如
Animal.prototype.run):是共享的。所有Lion实例都会共用这个方法,不会每个实例都重新创建一份,这也是原型继承节省内存的核心优势。 - 实例属性(比如
this.eats):不会共享。因为你在Lion构造函数里调用了Animal.call(this),这会给每个Lion实例单独创建一个eats属性,而非从原型链继承的共享属性。如果是直接用Lion.prototype = new Animal(),那eats就会变成原型上的共享属性,修改一个实例的eats会影响所有实例,显然不合理,所以你用Animal.call(this)的方式是正确的。
3. class语法糖的实现逻辑是否与这段代码完全一致?
核心逻辑相通,但细节上不完全一致。
ES6的class确实是原型继承的语法糖,但它做了不少规范和优化:
class内部定义的方法是不可枚举的(你手写的原型方法是可枚举的),用Object.keys(Lion.prototype)看不到class里的方法,但能看到你手写的run。class强制开启严格模式,内部代码默认运行在严格模式下;而手写构造函数需要手动添加'use strict'才能开启。class必须用new调用,直接当作普通函数执行会报错;手写的Lion如果不用new调用(非严格模式下),会污染全局变量。class支持super关键字,封装了调用父类构造函数、访问父类原型方法的逻辑,手写原型继承需要手动处理这些场景。
用class实现你的例子,代码是这样:
class Animal { constructor() { this.eats = true; } run() { console.log("Running"); } } class Lion extends Animal { constructor() { super(); // 等价于手写的Animal.call(this) this.roar = function () { console.log("Roaring"); } } }
这段class代码的底层逻辑和你补全后的手写代码非常接近,但class帮你处理了更多细节,让代码更规范、更不易出错。
内容的提问来源于stack exchange,提问作者Siva B
相关产品推荐
相关产品推荐

