寄生组合式继承默认只继承函数方法,非函数属性需额外处理以避免引用共享风险;可通过只读共享、构造时独立初始化或浅拷贝到子类原型三种方式管理,推荐不在原型上放置可变非函数属性。

寄生组合式继承本身不排斥原型上的非函数属性,关键在于“如何让子类原型正确继承父类原型的全部内容”,包括数据属性和方法。它默认只处理函数方法的继承,非函数属性(比如字符串、数字、对象字面量等)需要额外关注是否被复制、是否被共享、是否需独立初始化。
非函数属性会出现在哪里?
父类原型上可能定义了非函数属性,例如:
Parent.prototype.version = '1.0';
Parent.prototype.config = { timeout: 5000, retry: 3 };
Parent.prototype.name = 'Parent';
这些不是方法,但属于原型层级的共享数据。在寄生组合式继承中,它们不会自动“深拷贝”或“隔离”,而是沿原型链被所有实例读取——这本身没问题;但若子类修改 config 这样的引用类型,会影响所有父类及兄弟子类实例。
三种常见处理方式
-
保持只读共享:适用于常量类属性(如 version、name)。只要不主动赋值覆盖,子类实例访问
child.config仍指向父类原型上的同一对象,安全且节省内存。 -
构造时独立初始化:把非函数属性移到构造函数内,用
this挂载,避免原型共享。例如:this.config = {...Parent.prototype.config}。这样每个实例都有自己的副本,互不影响。 -
在寄生逻辑中浅拷贝到子类原型:在设置
Child.prototype = Object.create(Parent.prototype)后,手动把父类原型上的自有非函数属性复制过去(需过滤掉 constructor 和函数):
Object.getOwnPropertyNames(Parent.prototype).forEach(key => {
const desc = Object.getOwnPropertyDescriptor(Parent.prototype, key);
if (desc.value !== undefined && typeof desc.value !== 'function') {
Child.prototype[key] = desc.value;
}
});
注意:这种方式仅适合基础类型(string/number/boolean),对对象或数组仍是浅拷贝,仍存在引用共享风险。
为什么不能依赖 Object.create() 自动继承非函数属性?
Object.create(Parent.prototype) 确实会让子类原型继承父类原型的所有可枚举和不可枚举属性(包括非函数),但继承的是“引用关系”。比如 config 是一个对象,Child.prototype.config 和 Parent.prototype.config 指向同一个内存地址。一旦某个子类实例执行 this.config.timeout = 10000,实际改的是原型上的那个对象——所有实例都会看到这个变化。
更稳妥的实践建议
- 尽量不在原型上放可变的非函数属性(尤其对象、数组);
- 若必须放,明确文档说明其为“共享只读配置”,禁止运行时修改;
- 需要实例独有副本时,统一在子类构造函数中用
Object.assign()或展开运算符初始化; - ES6+ 环境下,可用
static属性替代原型上的常量,语义更清晰。

















