位置:首页 > JavaScript > JavaScript中如何使用Object.freeze冻结原型对象防止篡改

JavaScript中如何使用Object.freeze冻结原型对象防止篡改

时间:2026-08-12  |  作者:深海捕梦者  |  阅读:0

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

Ja vaScript 中怎么使用 Object.freeze 冻结原型对象防止被篡改

Object.freeze能锁住的,只有对象本身这一层属性。原型链上的属性,以及原型本身的变化,它都管不到。

也就是说,像原型对象,例如 obj.__proto__Object.getPrototypeOf(obj),并不会因为它而被直接冻结。原型被重新赋值或继续修改,它同样拦不住。

为什么 Object.freeze 不能冻结原型?

在 Ja vaScript 里,原型链的关联依赖内部属性 [[Prototype]]

Object.freeze能管住的,只是目标对象自己身上的可枚举和不可枚举属性,方法也算在内。它不会顺着原型链递归冻结,也不会把 __proto__prototype 这两个属性本身一并锁死。

例如:

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__)

如何真正保护原型不被篡改?

要做到这一点,需要组合使用多种机制,从不同层面加固。

  • 冻结原型对象本身:如果希望原型不可变,就对原型对象调用 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 是浅冻结:若原型属性是对象,其嵌套属性仍可变,需手动深冻或用库
  • prototype 仍需单独处理:箭头函数、class 声明的 prototype 默认不可写/不可配置,但依然可被 Object.defineProperty 覆盖(除非先 seal/freeze)
  • 类的静态成员不在 prototype 上:ES6 class 的静态方法/属性不在 prototype 上,需单独冻结 MyClass 本身
  • 不要冻结全局原型:在模块顶层冻结全局原型(如 Array.prototype)极不推荐——会影响其他代码,且多数环境禁止(如浏览器中会抛出 TypeError)

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多