Object.freeze()
Object.freeze()
Object.freeze()
方法,可以冻结一个对象。被冻结的对象再也不能被修改;不能添加新的属性,不能删除已有属性,不能修改已有属性的值、可枚举性、可配置性、可写性。此外,冻结一个对象后该对象的原型也不能被修改。
冻结之后,如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。
数组作为一种对象,被冻结,其元素不能被修改。没有数组元素可以被添加或移除。
1 2 3 4 5 6 7 8 9 10 11 |
var o = { user: {name: "zhang"} }; Object.freeze(o); o.user = {name: "wang"}; // 无效。因为o已经被冻结 o.user.name = "wang"; // 有效。user保存的内存地址。它指向的对象并未冻结 Object.isFrozen(o); // true // 不能更改原型 Object.setPrototypeOf(o, { x: 20 }) // TypeError o.__proto__ = { x: 20 } // TypeError |
1 2 3 4 5 6 |
var arr = []; Object.freeze(arr); arr.push(1); // 无效。 arr = [1,2,3]; // 有效。直接创建了一个新的数组,修改了指向 |
深冻结
要真正冻结一个对象,需要递归冻结每个类型为对象的属性(深冻结)。
当对象在引用图中不包含任何环(循环引用)时,就可以使用递归完成深冻结,否则将触发无限循环。
对deepFreeze()
的增强将是具有接收路径(例如Array)参数的内部函数,以便当对象进入不变时,可以递归地调用deepFreeze()
。你仍然有冻结不应冻结的对象的风险,例如[window]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// 深冻结函数. function deepFreeze(obj) { // 取回定义在obj上的属性名 var propNames = Object.getOwnPropertyNames(obj); // 在冻结自身之前冻结属性 propNames.forEach(function(name) { var prop = obj[name]; // 如果prop是个对象,冻结它 if (typeof prop == 'object' && prop !== null) deepFreeze(prop); }); // 冻结自身(no-op if already frozen) return Object.freeze(obj); } obj2 = { internal: {} }; deepFreeze(obj2); obj2.internal.a = 'anotherValue'; obj2.internal.a; // undefined |