Object.freeze不能冻结原型是因为它只作用于对象自身的属性,不处理[[Prototype]]内部链接或__proto__属性。需分别冻结原型对象并防止原型被替换才能真正保护原型链。

Object.freeze 只能冻结对象自身的属性,**无法冻结原型链上的属性或改变原型本身**。也就是说,它对原型对象(如 obj.__proto__ 或 Object.getPrototypeOf(obj))没有直接作用,也不能阻止原型被重新赋值或修改。
为什么 Object.freeze 不能冻结原型?
JavaScript 的原型是通过内部属性 [[Prototype]] 关联的,而 Object.freeze 的作用范围仅限于目标对象自身的可枚举/不可枚举属性(包括方法),不递归冻结其原型,也不锁定 __proto__ 或 prototype 属性本身。
例如:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
const parent = { foo: 'bar' };
const child = { baz: 42 };
Object.setPrototypeOf(child, parent);
Object.freeze(child);
// ✅ child 自身属性被冻结
child.baz = 99; // 无效(严格模式报错)
child.newProp = 'test'; // 无效
// ❌ 但原型仍可被篡改
parent.foo = 'hacked'; // 成功!child.foo 现在是 'hacked'
Object.setPrototypeOf(child, {}); // 仍可更换原型(freeze 不锁 __proto__)
如何真正保护原型不被篡改?
需组合使用多种机制,从不同层面加固:
立即学习“Java免费学习笔记(深入)”;
-
冻结原型对象本身:如果希望原型不可变,就对原型对象调用
Object.freeze(不是子对象) -
防止原型被替换:用
Object.preventExtensions+Object.seal+Object.freeze组合,或更彻底地——使用Object.setPrototypeOf(obj, null)切断原型链后冻结 -
创建不可变构造函数:在类/构造函数定义时冻结其
prototype,并禁用实例的原型修改能力 - 用 class + private fields(#)+ freeze 实例:现代方式,将关键状态封装为私有字段,实例化后冻结自身,原型只保留冻结过的公有方法
实用示例:安全冻结带原型的对象
以下是一个兼顾实例与原型防护的写法:
// 1. 定义并冻结原型对象
const AnimalProto = {
speak() { return `${this.name} makes a sound`; },
getType() { return this.type; }
};
Object.freeze(AnimalProto); // 冻结原型方法和属性
// 2. 创建实例,并冻结自身
function createAnimal(name, type) {
const instance = { name, type };
Object.setPrototypeOf(instance, AnimalProto);
return Object.freeze(instance); // 冻结实例自身
}
const dog = createAnimal('Buddy', 'dog');
console.log(dog.speak()); // "Buddy makes a sound"
dog.name = 'Max'; // ❌ 失败
AnimalProto.speak = () => 'hijacked'; // ❌ 失败(因 AnimalProto 已 freeze)
Object.setPrototypeOf(dog, null); // ❌ 在严格模式下会报错(因 dog 是 frozen,且 setPrototypeOf 需要 extensible)
注意边界情况
-
Object.freeze是浅冻结:若原型属性是对象,其嵌套属性仍可变(需手动深冻或用库) - 箭头函数、class 声明的 prototype 默认不可写/不可配置,但依然可被
Object.defineProperty覆盖(除非先 seal/freeze) - ES6 class 的静态方法/属性不在 prototype 上,需单独冻结
MyClass本身 - 在模块顶层冻结全局原型(如
Array.prototype)极不推荐——会影响其他代码,且多数环境禁止(如浏览器中会抛出 TypeError)

















