488 字
2 分钟
JS如何真正冻结对象
2025-03-15

const 的局限性#

对于复杂类型,const只是冻结了变量引用(内存地址),对象本身内部属性仍可修改

const author = { name: 'ocean', gender: 'male'};
author.age = 18; // 可以新增
author.name = 'xxx'; // 可以修改
delete author.gender; // 可以删除

不同场景的一些冻结方案#

WARNING

冻结后的对象性能略低于普通对象(需访问控制),权衡使用

1. Object.freeze()Object.seal() —— 浅冻结#

限制

对于嵌套对象只能冻结第一层属性

// 嵌套对象:
const objNested = {
name: '张三',
detail: { age: 25, city: '北京' }
};
Object.freeze(objNested);
objNested.detail.age = 26; // ✓ 嵌套对象可修改!
Object.seal(objNested)
objNested.detail.name = 'xxx'; // ✓ 嵌套对象可修改!

2.实现一个深冻结(Deep Freeze) 方法#

function DeepFreeze(obj) {
const propNames = Reflect.ownKeys(obj);
Object.freeze(obj);
// 递归冻结所有嵌套对象
propNames.forEach(name => {
const value = obj[name];
if (value && typeof value === 'object') {
DeepFreeze(value);
}
});
return obj;
}
// test:
const obj = {
name: '张三',
detail: { age: 25, city: '北京' },
hobbies: ['篮球', '游泳']
};
deepFreeze(obj);
obj.name = '李四'; // ✗ 失败
obj.detail.age = 26; // ✗ 失败
obj.hobbies.push('跑步'); // ✗ 失败
obj.newProp = '新属性'; // ✗ 失败

3.使用 Proxy 实现严格冻结#

function strictFreeze(obj) {
const handler = {
set(target, prop, value) {
throw new Error(`Cannot modify property "${prop}"`);
},
deleteProperty(target, prop) {
throw new Error(`Cannot delete property "${prop}"`);
},
defineProperty(target, prop, descriptor) {
throw new Error(`Cannot define property "${prop}"`);
}
};
return new Proxy(obj, handler);
}
const obj = { name: '张三', age: 25 };
const frozen = strictFreeze(obj);
frozen.age = 26; // Error: Cannot modify property "age"
delete frozen.name; // Error: Cannot delete property "name"

4. 利用第三方库(例如Immutable.js)#

import { Map, List } from 'immutable';
const data = Map({
name: '张三',
age: 25,
hobbies: List(['篮球', '游泳'])
});
// 所有修改操作都返回新对象
const newData = data.set('age', 26);
console.log(data.get('age')); // 25(原对象不变)
console.log(newData.get('age')); // 26(新对象)
const newHobbies = data.update('hobbies', list => list.push('跑步'));
console.log(data.get('hobbies')); // 原列表
console.log(newHobbies.get('hobbies')); // 新列表

如何选择#

场景推荐方案
配置对象Object.freeze()
深层嵌套对象deepFreeze()
严格报错Proxy 拦截
频繁修改Immutable.js
性能敏感Object.seal()
JS如何真正冻结对象
https://blog.oceanh.top/posts/frontend/js如何真正冻结对象/
作者
Ocean Han
发布于
2025-03-15
许可协议
CC BY-NC-SA 4.0
最后修改时间
2026-03-24 11:03:36