原型链继承是javascript最基础的继承方式,通过child.prototype = new parent()让子类原型指向父类实例,实现方法复用和instanceof判断;但存在引用属性共享、无法传参、原型链过长三大缺陷。

原型链继承是 JavaScript 最基础的继承方式,它的核心在于让子构造函数的 prototype 指向父构造函数的一个实例,从而建立对象间的委托关系。它不是复制,而是通过 __proto__ 链查找属性和方法。
优点:简单直接,能继承原型方法
实现成本低,只需一行关键代码:Child.prototype = new Parent()。子类实例可以自然访问父类原型上定义的所有方法,比如 sayName、toString 等,无需重复定义。
- 代码简洁,理解门槛低,适合快速构建轻量级继承结构
- 方法复用性好——所有子实例共享同一份原型方法,不重复创建函数对象
- 天然支持
instanceof和isPrototypeOf判断
缺点一:引用类型属性被所有实例共享
如果父构造函数中初始化了数组、对象、函数等引用类型属性(如 this.colors = ['red']),这些值会存在于父类实例中,并被所有子类实例通过原型链共用。一个实例修改,其他实例立刻可见。
- 例如:
child1.colors.push('green')后,child2.colors也会包含'green' - 这违反封装原则,容易引发隐蔽的数据污染问题
- 基本类型(如字符串、数字)不受影响,因为赋值时会屏蔽原型上的同名属性
缺点二:无法在创建子实例时向父构造函数传参
由于 Child.prototype = new Parent() 是在子类定义阶段执行的,此时无法获知将来创建 new Child(...) 时的具体参数,所以父构造函数得不到初始化所需的入参。
- 像
function Parent(name) { this.name = name }这类带参数的构造函数,在原型链继承下无法被正确初始化 - 子实例的
this.name会是undefined或默认值,而非传入值 - 后续手动赋值(如
child.name = 'Tom')属于补救,不是继承设计的一部分
缺点三:原型链过长影响可维护性与性能
多层原型链(如 A ← B ← C ← Object)会让属性查找路径变长,既增加引擎运行时开销,也加大调试和理解难度。
- 每次访问属性都要逐级向上遍历,现代引擎虽有优化,但深层链仍可能拖慢高频操作
- 开发者需时刻清楚“这个
this.xxx到底来自哪一层”,尤其在重写或扩展时易出错 - 构造函数与原型职责混杂,不利于模块拆分和单元测试
评估原型链继承是否适用,关键是看场景是否满足两个条件:父类不带初始化参数、且不包含需隔离的引用属性。一旦不满足,就该考虑借用构造函数、组合继承或更优的寄生组合继承。











