javascript通过原型链实现继承,核心是构造函数初始化实例属性、prototype挂载共享方法;组合继承(构造函数调用+原型链链接)兼顾属性隔离与方法复用,es6 class仅为语法糖,底层仍依赖原型机制。

JavaScript 本身没有传统意义上的“类”,但通过原型继承可以模拟出接近经典 OOP 的类结构。关键不在于语法像不像 class,而在于能否做到:属性隔离、方法复用、实例独立、类型可识别、扩展可控。真正的健壮性来自对原型链机制的尊重,而非绕过它。
用构造函数 + 原型对象定义“类”骨架
构造函数负责初始化实例独有属性(尤其是引用类型),原型对象负责挂载共享方法——这是避免内存浪费和状态污染的基础。
- 构造函数中只写 this.xxx = xxx,不定义函数(防止每个实例重复创建)
- 所有方法统一挂到 Constructor.prototype 上,比如
Person.prototype.say = function() { ... } - 确保每个实例的
__proto__正确指向构造函数的prototype(new 操作符自动完成)
通过组合继承解决核心缺陷
纯原型链继承会让所有实例共享父类实例属性(如数组、对象),纯构造函数继承又无法复用方法。组合继承是目前最稳妥的手动实现方式:
- 子类构造函数内用
Parent.call(this, ...)获取独立属性(如this.name、this.habits = []) - 子类原型设为
Object.create(Parent.prototype)(比new Parent()更干净,避免执行父类构造逻辑) - 立即修复
Child.prototype.constructor = Child,否则 instanceof 和 constructor 判断会出错
增强健壮性的关键细节
健壮不是靠加 try-catch,而是从设计源头堵住常见漏洞:
-
避免直接修改原型上的引用类型:比如
Parent.prototype.config = { lang: 'en' }是危险的;应让实例在构造时自行初始化配置对象 - 方法中始终用 this 访问实例属性,不依赖闭包或外部变量,保证方法可被任意上下文调用(如事件回调)
-
检查原型链终点:确保最终能到达
Object.prototype,且其__proto__为null,避免意外断链 - 用 hasOwnProperty 区分自有属性与继承属性,尤其在遍历或序列化时,防止误操作继承来的不可枚举方法
ES6 class 只是语法糖,底层仍是原型
即便使用 class Person extends Animal,Babel 编译后仍是基于 Object.setPrototypeOf 和 Parent.call 的组合逻辑。理解原型继承,才能真正看懂 transpiled 代码、调试继承链、处理第三方库的原型扩展冲突。











