寄生组合式继承通过parent.call(this)继承私有属性与方法,object.create(parent.prototype)继承公有方法,严格分离实例独有状态与共享行为。
寄生组合式继承能真正实现公有属性与私有方法的分离,关键不在“写得多”,而在“分得清”——实例属性归构造函数管,共享方法归原型链管,两者互不干扰。
公有属性必须定义在原型上
所有子类实例共用、不随实例变化的数据或行为,应挂载到父类原型。比如通用工具方法、默认配置、只读标识等。
- 直接赋值给 Parent.prototype.xxx,避免用
Parent.prototype = {...}全量覆盖(会丢失 constructor) - 不要在原型上放引用类型(如
arr: []或obj: {}),否则仍会被共享;若需默认值,应在构造函数中初始化 - 子类无需重写父类原型方法即可直接使用,也支持被子类原型方法通过
super.xxx()(ES6 class 中)或Parent.prototype.xxx.call(this)(函数式中)调用
私有属性和方法必须在构造函数内声明
每个实例独有的状态(如 name、age、内部缓存)和仅本实例可用的逻辑(如校验、计算),必须在 function Parent() { ... } 内部用 this.xxx = xxx 或 const helper = () => {...} 定义。
- 私有方法建议用闭包封装:在构造函数内定义函数,不挂 this,外部无法访问,但内部方法可调用
- 引用类型私有属性(如
this.items = [])必须在构造函数中新建,确保实例间隔离 - 子类构造函数中必须显式调用
Parent.call(this, ...),才能把这一套私有机制继承过来
寄生组合式继承的两步落地要点
它不是语法糖,而是明确分工的协作机制。只需两个核心动作,就能守住边界:
-
用
Parent.call(this, ...)拿私有部分:保证子类实例拥有独立的 name、friends、内部状态等,支持传参,且不污染父类原型 -
用
Object.create(Parent.prototype)接公有部分:让子类原型干净地复用 sayName、getInfo 等方法,不执行父构造函数,也不共享引用属性 - 别忘了补一句
Child.prototype.constructor = Child,否则 instanceof 和调试器会误判构造函数
一个清晰的结构示例
下面代码展示了分离逻辑如何自然呈现:
function Animal(name, type) {
// ✅ 私有属性:每个实例独有
this.name = name;
this.type = type;
this._id = Math.random().toString(36).substr(2, 9); // 内部唯一标识
// ✅ 私有方法:闭包封装,外部不可见
const validate = () => typeof name === 'string' && name.length > 0;
this.speak = () => {
if (validate()) console.log(`${this.name} makes a sound`);
};
}
// ✅ 公有方法:所有实例共享,定义在原型
Animal.prototype.getType = function() {
return this.type;
};
Animal.prototype.toString = function() {
return `Animal(${this.name}, ${this.type})`;
};
// 子类继承
function Dog(name, type, breed) {
Animal.call(this, name, type); // ? 拿私有
this.breed = breed; // ? 新增私有
}
Dog.prototype = Object.create(Animal.prototype); // ? 接公有
Dog.prototype.constructor = Dog;
// ✅ 子类可扩展公有方法,不影响父类
Dog.prototype.bark = function() {
console.log(`${this.name} barks!`);
};











