ES5用Object.create模拟原型继承最稳妥,需用Object.create(Parent.prototype)创建原型、修复constructor、调用Parent.call(this)继承实例属性;ES6 class是语法糖,super()自动初始化this并建立原型链,但约束更严格。

ES5 用 Object.create 模拟原型继承最稳妥
ES5 没有原生 class,靠修改构造函数的 prototype 和借用 Object.create 实现继承链。核心是让子类实例的 __proto__ 指向父类原型,同时不污染父类实例。
常见错误是直接赋值 Child.prototype = Parent.prototype,这会导致子类改原型时影响父类;或忘记修复 constructor 指针,导致 instance.constructor === Parent 而非 Child。
正确做法:
- 用
Object.create(Parent.prototype)创建干净的原型对象 - 手动赋值
Child.prototype.constructor = Child - 在子类构造函数中用
Parent.call(this, ...args)继承实例属性
function Parent(name) {
this.name = name;
}
Parent.prototype.say = function() { return 'hi'; };
function Child(name, age) {
Parent.call(this, name); // 继承实例属性
this.age = age;
}
Child.prototype = Object.create(Parent.prototype); // 继承原型方法
Child.prototype.constructor = Child; // 修复 constructor
ES6 class 语法糖本质仍是原型继承
class 不是新机制,只是对 ES5 原型继承的封装。它强制要求子类构造函数必须调用 super(),否则报错 ReferenceError: Must call super constructor in derived class before accessing 'this'。
立即学习“Java免费学习笔记(深入)”;
关键差异在于:ES6 的 super() 不仅调用父构造函数,还初始化了 this(即绑定了原型链),而 ES5 中 Parent.call(this) 只处理属性,原型链需额外设置。
注意点:
-
super()必须在使用this前调用,顺序错误直接报错 - 静态方法和 getter/setter 会被正确继承,但需确保父类也有对应定义
- 不能在子类
constructor外访问super.xxx(如直接在方法里写super.method()是合法的,但不能在顶层写)
class Parent {
constructor(name) {
this.name = name;
}
say() { return 'hi'; }
}
class Child extends Parent {
constructor(name, age) {
super(name); // 必须第一句
this.age = age;
}
}
ES5 和 ES6 继承在 new.target 和 instanceof 行为一致
两者都保持正确的原型链:子类实例 instanceof Child 和 instanceof Parent 都为 true,Object.getPrototypeOf(child) === Child.prototype,再往上是 Parent.prototype。
区别在于元信息层面:new.target 在 ES6 class 构造函数中能准确指向当前被 new 的类(包括子类),而 ES5 构造函数中 new.target 兼容性差,且无法自然表达“谁是真正被实例化的类”。
这意味着如果你依赖 new.target 做抽象基类校验(比如禁止直接 new 父类),ES6 更可靠。
箭头函数、bind 和继承混用容易破坏 this 绑定
无论 ES5 还是 ES6,如果在父类方法中用了箭头函数,该方法无法被子类重写——因为箭头函数没有自己的 this,且绑定发生在定义时,不会随调用上下文改变。同样,用 bind 固定 this 后的方法也无法被子类通过原型链覆盖。
典型陷阱:
- 父类写
this.handleClick = () => {...},子类在prototype上定义同名方法无效 - 父类用
someMethod.bind(this)返回绑定函数并赋给实例属性,子类无法通过原型链拦截 - ES6 中在
constructor里用this.xxx = () => {},等价于上一条
需要可继承的行为,必须定义在 prototype 上,且用普通函数。
extends 看似简单,但底层约束更严格;ES5 手动操作原型链看似繁琐,反而留出更多控制空间。实际项目中,如果目标环境支持,优先用 ES6;但调试时得清楚它背后仍是 Object.create + call + constructor 修复那一套。











