原型继承本身不能实现深冻结,深冻结依赖递归调用 Object.freeze() 作用于对象自身属性,不涉及原型链;冻结后子类实例仍可调用原型方法,若需冻结整个继承体系需手动冻结原型但通常不推荐。

原型继承本身不能实现深冻结,它和 Object.freeze() 是两条独立的机制。深冻结靠的是递归调用 Object.freeze(),不是靠原型链或继承关系来保护数据。
深冻结不依赖原型继承
JavaScript 的 Object.freeze() 只作用于对象自身的可枚举属性,不会影响原型链上的属性,也不会因为对象是通过构造函数或 class 创建、是否继承自某个父类而改变冻结行为。也就是说:
- 即使子类从父类原型继承了方法,
deepFreeze(childInstance)也只冻结实例自身属性,不冻结childInstance.__proto__或Parent.prototype - 冻结后,子类实例仍能调用原型上的方法(因为方法没被冻结,只是不可改写实例自有属性)
- 如果想冻结整个继承体系,需手动对原型对象也调用
Object.freeze(),但这通常不推荐——会破坏框架或库的运行逻辑
真正起作用的是递归冻结逻辑
实现深冻结的关键是判断并遍历嵌套结构,对每个子对象/数组再次冻结。典型安全写法包括:
- 跳过
null、undefined、原始类型(string/number/boolean 等) - 跳过内置对象如
Date、RegExp、Promise,它们不能被有意义地冻结 - 检查
Object.isFrozen(obj)避免重复冻结 - 用
Object.keys(obj)或Object.getOwnPropertyNames(obj)获取自有属性,不遍历原型链 - 对
Array.isArray(value)和value.constructor === Object分别处理数组与普通对象
配合原型继承时的注意事项
如果你用构造函数或 class 定义状态对象,并希望实例深度不可变,建议:
- 在构造函数返回前,对实例调用深冻结函数,而不是依赖原型上定义的冻结方法
- 避免在原型上定义可变状态(比如
this.cache = {}),否则冻结实例后,原型上的共享状态仍可能被修改 - 若需冻结“类模板”,可冻结其
prototype,但必须确认没有运行时动态添加方法的需求
一个轻量可用的 deepFreeze 实现
不依赖任何继承模型,适用于任意普通对象或数组:
function deepFreeze(obj) {
if (obj == null || typeof obj !== 'object') return obj;
if (Object.isFrozen(obj)) return obj;
// 跳过 Date、RegExp、Map、Set 等不可安全冻结的内置类型
if (obj instanceof Date || obj instanceof RegExp) return obj;
Object.getOwnPropertyNames(obj).forEach(prop => {
if (typeof obj[prop] === 'object' && obj[prop] !== null) {
deepFreeze(obj[prop]);
}
});
return Object.freeze(obj);
}
调用 deepFreeze(new MyClass()) 后,该实例及其所有嵌套普通对象/数组都变为只读,和它怎么继承来的无关。


















