Javascript Object.freeze()不会阻止对象的更改

时间:2016-11-03 17:15:37

标签: javascript oop

我正在尝试理解ECMAscript的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。任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:0)

这很奇怪,但是冻结会阻止变异元素,向数组添加元素不会发生变异(奇怪的是)......

例如在ES6中,当您定义一个不会发生变化的变量时,您使用" const"来声明它。而不是"让"。如果你说:

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

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

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

它不会抛出错误。

答案 2 :(得分:0)

使用writable:false将对象的属性描述符设置为configurable:falseObject.defineProprties;然后在对象上调用Object.preventExtensions。请参阅How to create static array in javascript