1 作用
冻结一个对象,使对象不可扩展。
2 特性
- 对象的属性不可再被新增、删除
- 对象的属性的值不可再被修改
- 对象的属性的描述符中任意配置项都不可被重新定义
3 代码示例
3.1 冻结对象
Object.freeze()
代码如下:
'use strict'
let initialData = {a: 123};
initialData.a = 234;
console.log(initialData.a);
Object.freeze(initialData);
/**
* 严格模式下会报错
* TypeError: Cannot assign to read only property 'a' of object '#<Object>'
*/
initialData.a = 345;
console.log(initialData.a);
3.2 冻结判断
Object.isFrozen()
代码如下:
// Object.isFrozen()
Object.isFrozen(initialData); // true
4 深冻结和浅冻结
直接使用的话只能实现浅冻结,只能冻结第一层。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JavaScript - 冻结对象</title>
</head>
<body>
<script>
// 定义一个对象
const info = {
name: '梦缘',
age: 29,
hobby: [ '徒步' ]
};
// 冻结对象
Object.freeze(info);
// 新增一个属性:不生效
info.nickname = '熊二';
// 删除一个属性:不生效
delete info.name;
// 更改name属性的值:不生效
info.name = '梦念兮';
// 更改age属性的值:不生效
info.age = 17;
// 更改hobby属性的值:不生效
info.hobby = [ '音乐' ];
// 对hobby属性的值添加元素:生效
info.hobby.push('电影');
// 打印对象
console.log(info);
// 打印对象的每一个属性的描述符
Object.keys(info).forEach(key => {
console.log(Object.getOwnPropertyDescriptor(info, key))
});
// 更新属性的【值】描述符:报错
Object.defineProperty(info, 'hobby', {
value: [ '徒步' ]
});
// 更新属性的【值是否可更新】描述符:报错
Object.defineProperty(info, 'hobby', {
writable: true
});
// 更新属性的【是否可枚举】描述符:报错
Object.defineProperty(info, 'hobby', {
enumerable: false
});
// 更新属性的【是否可更改描述符】描述符:报错
Object.defineProperty(info, 'hobby', {
configurable: true
});
</script>
</body>
</html>
效果如下:
其中的hobby属性还是可以进行push。
深冻结需要更深层次操作:
代码如下:
function deepFreeze(obj) {
// 首先冻结对象本身
Object.freeze(obj);
// 获取对象的所有属性
const props = Object.getOwnPropertyNames(obj);
// 递归地冻结属性值为对象的属性
for (const prop of props) {
const value = obj[prop];
if (value && typeof value === 'object') {
deepFreeze(value);
}
}
return obj;
}
// 示例对象
const obj = {
a: 1,
b: {
c: 2,
d: [3, 4, 5]
}
};
// 冻结对象
const frozenObj = deepFreeze(obj);
// 尝试修改对象
frozenObj.a = 10; // 不可修改
frozenObj.b.c = 20; // 不可修改
frozenObj.b.d.push(6); // 不可修改
console.log(frozenObj); // 输出:{a: 1, b: {c: 2, d: [3, 4, 5]}}
5 注意
冻结只会冻结已有的属性,不会拦截到后续添加的属性。如果需要完全禁止属性的添加和删除,可以通过使用Object.seal()函数进行浅冻结,或者使用Object.preventExtensions()函数来禁止对象扩展。