Object.freeze()不会冻结传递对象中的对象有什么好处?

时间:2014-02-18 06:36:06

标签: javascript

我在MDN上学习了更多有关JavaScript Object构造函数的方法,我注意到Object.freeze's description的最后一句是:

  

请注意,仍然可以修改作为对象的值,除非它们也被冻结。

这样的行为似乎应该选择加入。必须递归地手动冻结冻结对象的对象有什么好处?

如果我冻结一个物体,我为什么还要让它里面的物体仍然可变?

4 个答案:

答案 0 :(得分:13)

我认为如果递归是默认策略,则某些复杂的对象无法按预期运行。 考虑以下情况:

<div id="root">
    <div id="stem">
        <div id="leaf>
        </div>
    </div>
</div>

由于某种原因我想冻结stem,所以我写了这些代码:

Object.freeze(document.getElementById('stem'));

如果它以递归方式冻结,leaf也会被冻结,似乎没问题:如果我要冻结stem,我也想冻结它的孩子。

但请稍等,请注意stem还有另一个属性 - 它也有parentElement。那会发生什么?当我冻结stem时,我也会冻结stem.parentElementstem.parentElement.parentElement ......这绝不是我想要的。

答案 1 :(得分:6)

答案就在于这一点

Note that values that are objects can still be modified, unless they are also frozen.

<强>更新

  

没有关于freeze()方法的设计决定的任何官方信息

我认为,基本上对于性能原因他们已经做出了这个决定,如果我们想让内部对象也被冻结,我们将不得不递归地应用方法 。所以这是一个很大的开销,所以做出了设计决定以避免这种情况。

  

如果不是性能,该方法就会表现出来   不同。

答案 2 :(得分:1)

在考虑更多之后,可能是为了防止冻结在其他地方也被引用的引用对象(从而禁用使用同一对象的另一部分代码)。我对此的回应是:

我并不是建议这样做。如果完全捕获对象的状态,Object.freeze()会更有意义。引用(对象)本身可以是不可变的,但引用的对象不会被冻结。

如果我这样做......

var friend = {
    name: 'Alec',
    likes: {
        programming: true,
        reading: true,
        cooking: false
    }
};

// Pass as frozen object
doStuff(Object.freeze(friend));

document.addEventListener('click', function () {
    friend.likes.clicking = true;
});

...我不希望name被更改我不希望朋友的likes被{{更改} 1}}。但我仍然希望能够从事件监听器更改doStuff()(就像我可以更改likes),例如,没有namedoStuff()的对象引用也改变了。

编辑:在阅读了Shaik的回答之后,我理解他们为什么这样做。现在,为了获得本例中我需要的功能,我会这样做:

friend

这有什么固有的问题吗?

答案 3 :(得分:0)

这一切都取决于具体情况。您可能希望冻结对象以防止添加或删除新属性集,但是您可能希望更改现有属性。如果你不这样做,就冻结吧! IIRC,你只能冻结父对象。子对象也需要递归冻结。