可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I was learning more about the methods of JavaScript's Object
constructor on MDN and I noticed that the last sentence of Object.freeze's description reads:
Note that values that are objects can still be modified, unless they are also frozen.
A behavior like that seems like it should be opt-in. What exactly is the benefit of having to manually freeze a frozen object's objects recursively?
If I'm freezing an object, why would I want the objects inside of it to still be mutable?
回答1:
The answer lies in the point itself
Note that values that are objects can still be modified, unless they are also frozen.
Update:
There is no official information any where regarding the design decision of freeze() method
I think, basically for performance reasons they have took this decision, if we have wanted to make the internal objects also freezed, we would have to apply the method recursively. So this is a big overhead, so the design decision was made to avoid this.
If it was not the performance, the method would have behaved differently.
回答2:
I think if recursive is the default strategy, some complex Objects could not behave as expected. Think about following situation:
<div id="root"> <div id="stem"> <div id="leaf> </div> </div> </div>
and for some reason I want to freeze the stem
, so I wrote these code:
Object.freeze(document.getElementById('stem'));
If it freezes recursively, the leaf
would be frozen too, and it seems OK: if I want to freeze the stem
, I also want to freeze it's children.
But wait, note that stem
has another property -- It has parentElement
too. So what will happen? When I freeze stem
, I also freeze stem.parentElement
, and stem.parentElement.parentElement
... This is never what I want.
回答3:
After thinking about it more, it's probably to prevent the freezing of referenced objects that are also being referenced elsewhere (thus disabling another section of code that uses the same object). My response to that would be:
I wasn't suggesting it work that way. Object.freeze()
would make more sense if the state of the object is captured completely. The references (to the objects) themselves could be immutable, but the object referenced would not be frozen.
If I did this...
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; });
...it would make sense that I don't want name
to be changed AND I don't want the friend's likes
to be changed by doStuff()
. But I would still want to be able to change likes
(just like I could change name
) from an event listener, for example, without doStuff()
's object reference to friend
changing too.
Edit: After reading Shaik's answer, I understand why they do it the way they do. Now, in order to have the functionality I would need in this example, I would do this:
function deepFreeze (obj) { if (typeof obj !== 'object') return console.error('An object must be passed to deepFreeze()'); for (var key in obj) { var val = obj[key]; if (typeof val === 'object') deepFreeze(val); } return Object.freeze(obj); }
Are there any inherent problems with this?
回答4:
It all depends on the situation. You may want to freeze an object to prevent a new property set from being added, or being remove, however you may want existing properties to be altered. If you don't, just freeze them! IIRC, you can only freeze the parent object. Child objects would need a recursive freeze as well.