原型链继承的弊端是引用类型属性被所有实例共享且无法向父类传参;组合继承通过构造函数继承(保证属性独立与动态传参)和原型链继承(复用方法)解决,用object.create避免冗余执行。

原型链继承最典型的弊端是引用类型属性被所有实例共享,以及无法在创建子类实例时向父类构造函数传参。组合继承通过“构造函数继承 + 原型链继承”双管齐下,既让每个实例拥有独立的属性,又能复用父类的方法。
引用类型属性会被所有实例共享
当父类构造函数中定义了数组、对象等引用类型属性,并通过原型链继承给子类时,这些属性实际存在于子类的 prototype 上——也就是所有子类实例共用的一份内存。一个实例修改了它,其他实例立刻可见。
- 例如
Parent中有this.colors = ['red', 'blue'],子类Child用Child.prototype = new Parent()继承后,child1.colors.push('green')会导致child2.colors也多出一项 - 这不是预期行为:每个实例理应拥有自己独立的状态
无法在实例化时向父类传参
原型链继承把父类实例“一次性”赋给了子类的 prototype,参数只能在设置原型时固定写死,不能随每个子类实例动态变化。
- 比如
Child.prototype = new Parent('default'),之后无论new Child()还是new Child('Alice'),父类的name都是'default' - 子类实例无法个性化初始化父类字段,丧失灵活性
组合继承如何修复这两个问题
组合继承分两步走:先在子类构造函数里调用父类构造函数(解决属性独立和传参),再把父类原型挂到子类原型链上(解决方法复用)。
-
第一步:构造函数继承 —— 在
Child构造函数内执行Parent.call(this, name, age),这样每个child实例都拥有自己的一份name、age和friends数组,互不干扰 -
第二步:原型链继承 —— 使用
Object.create(Parent.prototype)设置Child.prototype,把sayName等方法继承下来,避免重复定义,实现复用 - 别忘了修正
constructor指针:Child.prototype.constructor = Child,否则instance.constructor会指向Parent
为什么不是直接用 new Parent() 设置原型
如果写成 Child.prototype = new Parent(),会再次执行父类构造函数,造成属性冗余(比如又新建一个 friends 数组挂在原型上),而这个数组仍是共享的——这正是组合继承要避开的陷阱。用 Object.create 只复制原型对象,不执行构造逻辑,干净利落。











