默认情况下,JavaScript 中的对象是可变的。我们可以更改原始值(字符串,数字等)和对象。我们来看看这个对象:
let obj = { num: 10, obj: { content: "mutable object" } }
你可以轻松地改变它:
obj.num = 5; obj.obj = { content: "changed!" } console.log(obj); // { // num: 5, // obj: { // content: "changed!" // } // }
非常明确是吧?那么,我们有什么办法使对象不可变呢?
1、让我们试用 const
!
很好的尝试,但是不起作用。如果你尝试一下,你会发现:这种办法根本就不起作用。const
关键字只是修改了某个变量名和其值之间的链接,而不是实际值。您仍然可以像上面所做的那样在 const
对象中更改这两个原始值和对象。例如:
const obj = { num: 10, obj: { content: "mutable object" } } obj.num = 5; obj.obj = { content: "changed!" } console.log(obj); // { // num: 5, // obj: { // content: "changed!" // } // }
2、继续尝试:Object.freeze()。
有很多关于 ES2015 新特性的文章和讨论。我们知道 ES2015 比 ES5 更好。例如,我们可以使用一个Object
方法来实现我们的目的:Object.freeze()
。该方法使对象的原始属性不可变。我们把这个方法应用到我们原来的 obj
对象上:
Object.freeze(obj); obj.num = 5; obj.obj = { content: "changed!" } console.log(obj); // { // num: 10, // obj: { // content: "changed!" // } // }
结果比原先的尝试稍后好一点,原始值现在已经修复,不可更改,但是我们仍然可以更改嵌套对象。
3、最终解决方案
为了使对象完全不可变,我们还需要freeze()
所有的嵌套对象。例如:
function deepFreeze(obj) { var propNames = Object.getOwnPropertyNames(obj); propNames.forEach(function(name) { var prop = obj[name]; if (typeof prop == 'object' && prop !== null) { deepFreeze(prop); } }); return Object.freeze(obj); }
使用这个函数,现在我们可以创建完全不可变的对象:
deepFreeze(obj); obj.num = 5; obj.obj = { content: "changed!" } console.log(obj); // { // num: 10, // obj: { // content: "mutable object" // } // }
总结:
采用递归freeze()所有嵌套对象