javascript如何实现继承_ES5和ES6方式有何不同【教程】

9次阅读

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

javascript如何实现继承_ES5和ES6方式有何不同【教程】

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.targetinstanceof 行为一致

两者都保持正确的原型链:子类实例 instanceof Childinstanceof Parent 都为 trueObject.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 上,且用普通函数。

ES6 的 extends 看似简单,但底层约束更严格;ES5 手动操作原型链看似繁琐,反而留出更多控制空间。实际项目中,如果目标环境支持,优先用 ES6;但调试时得清楚它背后仍是 Object.create + call + constructor 修复那一套。

text=ZqhQzanResources