javascript 中利用 weakmap 实现私有继承,核心做法是在父类构造函数中为实例分配一个唯一的私有数据容器,子类通过闭包或原型方法访问该容器以读写私有状态。具体而言,在 parent 的构造函数内调用 privatedata.set(this, {}) 存储初始值,子类 child 继承 parent 后,其方法内部通过 this 作为键从 weakmap 中获取数据,从而实现真正的私有性且不影响垃圾回收。

如何确保子类能正确访问父类的私有数据
子类必须通过原型链上的方法间接访问 WeakMap 中的对象,而不是直接持有 WeakMap 实例的引用。只要 WeakMap 的作用域被限制在模块或闭包中,外部代码就无法通过 this 获取到私有数据。关键在于子类的方法定义位置,它们需要能够捕获包含 WeakMap 的变量环境。

const privateData = new WeakMap();
function Parent(name) {
privateData.set(this, { name: name });
}
Parent.prototype.getName = function() {
return privateData.get(this).name;
};
function Child(name, age) {
Parent.call(this, name);
privateData.get(this).age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getAge = function() {
return privateData.get(this).age;
};
const child = new Child('Alice', 25);
console.log(child.getName()); // Alice
console.log(child.getAge()); // 25
console.log(privateData.has(child)); // true为什么使用 WeakMap 而不是普通对象或 Symbol
使用普通对象存储私有数据会导致内存泄漏,因为强引用会阻止实例被垃圾回收;而 Symbol 虽然提供了命名空间的隔离,但依然可以通过 Object.getOwnPropertySymbols 遍历并修改属性,不具备真正的不可见性。WeakMap 的键是弱引用,当实例不再被其他对象引用时,对应的私有数据会自动被清理,同时外部代码无法枚举或访问这些键值对。
立即学习“Java免费学习笔记(深入)”;

// 对比:Symbol 方式(非真正私有)
const _name = Symbol('name');
class ParentSym {
constructor(name) {
this[_name] = name;
}
getName() {
return this[_name];
}
}
// 外部仍可访问
const obj = new ParentSym('Bob');
const symKey = Object.getOwnPropertySymbols(obj)[0];
console.log(obj[symKey]); // Bob基于 Child 实例初始化时的具体行为分析
当执行 new Child('Alice', 25) 时,首先触发 Parent.call(this, 'Alice'),此时 WeakMap 中为该实例创建了一个新条目,初始值为 { name: 'Alice' }。随后执行 Child 构造函数体,通过 privateData.get(this) 获取该条目并添加 age 属性。整个过程确保了私有数据的封装性和自动回收特性,且子类无需知道 WeakMap 的具体实现细节。


















