2016-11-03 43 views
2

我想了解ECMAscript的Object.freeze方法。Javascript Object.freeze()不会阻止更改对象

我的理解是,它基本上停止对对象的所有属性的更改。 MDN文档说:

防止将新属性添加到它;防止现有属性被删除;并防止改变现有属性或其可枚举性,可配置性或可写性。

这似乎并非如此,但也许我误解了文档。

这是我的目标,其枚举财产exampleArray

function myObject() 
{ 
    this.exampleArray = []; 
} 

var obj = new myObject(); 
obj.exampleArray[0] = "foo"; 

现在,如果我冻结对象,我预计exampleArray属性太冻,因为它不能再以任何方式改变。

Object.freeze(obj); 
obj.exampleArray[1] = "bar"; 
console.log(obj.exampleArray.length); // logs 2 

“bar”已被添加到数组中,因此冻结对象已被更改。我的直接解决方案是冻结所需的属性:

Object.freeze(obj.exampleArray); 
obj.exampleArray[2] = "boo"; 

现在根据需要更改数组会引发错误。

但是,我正在开发我的应用程序,我还不知道将分配给我的对象。我的用例是我有一些游戏对象在游戏开始时被初始化(来自XML文件)。在此之后,我不想意外地改变他们的任何属性。

也许我误用了冻结方法?我希望能够冻结整个对象,这是一种递归冻结。我能想到的最佳解决方案是循环访问属性并冻结每个属性。

我已经搜索了这个问题,唯一的答案就是它是一个执行错误。我正在使用最新版本的Chrome。任何帮助表示赞赏。

+0

本页面下半部分:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze它表示:**以下示例显示冻结的对象值对象可能会发生变化(冻结很浅)。**所以它似乎按照设计工作。 –

回答

4

Object.freeze是一个浅层冻结。

如果您在docs看说明,上面写着:

值不是对数据属性来更改。访问器属性(getter和setter)的工作原理是相同的(并且仍然给出你正在改变值的错觉)。 请注意,作为对象的值仍可以修改,除非它们也被冻结。

如果你想深冻结的对象,这里的a good recursive example

function deepFreeze(o) { 
 
    Object.freeze(o); 
 

 
    Object.getOwnPropertyNames(o).forEach(function(prop) { 
 
    if (o.hasOwnProperty(prop) 
 
    && o[prop] !== null 
 
    && (typeof o[prop] === "object" || typeof o[prop] === "function") 
 
    && !Object.isFrozen(o[prop])) { 
 
     deepFreeze(o[prop]); 
 
     } 
 
    }); 
 

 
    return o; 
 
} 
 

 
function myObject() { 
 
    this.exampleArray = []; 
 
} 
 

 
var obj = deepFreeze(new myObject()); 
 
obj.exampleArray[0] = "foo"; 
 
console.log(obj); // exampleArray is unchanged

0

这是非常奇怪的,但冻结防止变异的元素,将元素添加到一个数组不变(足够奇怪)...

例如在ES6中,当你定义一个不会改变的变量时,用“const”而不是“let”声明它。如果你说:

const foo = 'foo'; const foo = 'bar;

,因为你使用const,它会抛出一个错误。当你说

const foo = ['foo']; foo.append('bar');

它不会引发错误。