纯原生JS模拟class继承需四步演进:第一步仅原型链导致实例属性缺失;第二步组合借用构造函数与原型链解决属性隔离但constructor丢失;第三步修复constructor指向并手动复制静态方法;第四步校验super调用顺序、模拟super.method()及静态super上下文。

用纯原生 JavaScript(ES5 及之前)手工模拟 class 继承,本质是还原 ES6 extends 背后的运行逻辑:既要让子类实例拥有父类的实例属性,又要正确链接原型链,还得处理构造函数调用顺序、this 绑定、静态方法继承等细节。整个过程不是一步到位,而是逐步补全缺陷的演进。
第一步:仅靠原型链继承(基础但有严重缺陷)
只设置子类原型指向父类原型,看似能复用方法,但完全不处理实例属性:
- 父类构造函数不会执行,子类实例拿不到
this.name等初始化属性 - 所有子类实例共享父类原型上的引用类型属性(如数组、对象),造成数据污染
-
instanceof判断可能失真,且无法继承静态方法
第二步:组合借用构造函数 + 原型链(寄生组合继承雏形)
在子类构造函数中用 Parent.call(this, ...args) 获取父类实例属性,在外部用 Object.create(Parent.prototype) 设置原型链:
- 解决了实例属性隔离问题:每个子类实例都有独立的
this.name、this.colors - 方法复用仍靠原型链,节省内存
- 但存在两个关键漏洞:子类原型的
constructor指向丢失(变成Parent),以及静态方法无法被子类继承
第三步:修复 constructor 和静态属性继承
在设置原型后手动修正 Child.prototype.constructor = Child;静态方法需显式复制:
-
Object.assign(Child, Parent)可把父类静态方法挂到子类上(注意避免覆盖已有同名静态方法) - 此时
new Child() instanceof Parent为true,Child.sayHello()也能调用成功 - 但仍有隐患:若父类静态方法内部用了
this,直接赋值过去可能导致上下文错乱(需绑定或包装)
第四步:完整模拟 super 行为与 this 初始化约束
ES6 中 super() 不仅调用父构造函数,还决定了 this 是否可用。手工模拟需强制校验:
- 在子类构造函数开头加判断:若未先调用
Parent.call(this),就抛出ReferenceError - 模拟
super.method():在子类方法中手动调用Parent.prototype.method.call(this, ...args) - 模拟静态方法中的
super:改用Parent.staticMethod.call(Child, ...args),并确保子类静态方法能访问父类静态上下文

















