Assign new property to empty object which has frozen prototype

匿名 (未验证) 提交于 2019-12-03 09:21:58

问题:

Why can't I assign new properties to non-frozen object, which has frozen prototype:

Working without Object.freeze:

'use strict' //This object will be prototype of next objects var defaults = {   name: 'def name',    sections: {     1: {       secName: 'def sec name'     }   } };  //So we have an empty object with prototype set to our default object. var specificObject = Object.create(defaults);   specificObject.sections = {}; console.log(specificObject.hasOwnProperty('sections')); //true  specificObject.sections['1'] = Object.create(defaults.sections['1']); 

Above code works as expected, but I want to make sure that defaults won't be accidentally changed. So I want to freeze my defaults object:

'use strict' //This object will be prototype of next objects var defaults = {   name: 'def name',    sections: {     1: {       secName: 'def sec name'     }   } };  //!!!!!!!!!!!! Object.freeze(defaults);  //So we have an empty object with prototype set to our default object. var specificObject = Object.create(defaults);  //TypeError: Cannot assign to read only property 'sections' of #<Object> specificObject.sections = {}; console.log(specificObject.hasOwnProperty('sections')); //true  specificObject.sections['1'] = Object.create(defaults.sections['1']); 

What I don't get is why can't I assign to specificObject if its prototype is frozen?

//EDIT: Notice that specific object is not frozen:

'use strict' //This object will be prototype of next objects var protoObj = {a: 1, o: {}}; Object.freeze(protoObj);  console.log(Object.isFrozen(protoObj)); //true  var n = Object.create(protoObj); console.log(Object.isFrozen(n)); //false 

回答1:

What I don't get is why can't I assign to specificObject if its prototype is frozen?

Because property attributes are inherited. Yes, it's odd.

If you freeze an object, it will set the [[writable]] attribute of all data properties to false.

If you assign to an object property, but that property does not exist on the object, it will go and look it up on the prototype - it might be defined as setter there. When this lookup will return and say that there is a property of that name but it is non-writable, your assignment will fail (and throw in strict mode).

What can you do against this?

  • Use Object.defineProperty instead of assignment, it doesn't check the prototype
  • or similarly, use the second parameter of Object.create to create the own property
  • freeze the defaults only after you've assigned to specificObject.


回答2:

my understanding is that specificObject.sections is pointing to its' prototype which is defaults and it is frozen object. You define a new object {} but you try to assign it to defaults.sections. SpecificObject.sections is pointing exactly there.

If you create new ownProperty on specificObject it will work:

'use strict' //This object will be prototype of next objects var defaults = {   name: 'def name',   sections: {     1: {       secName: 'def sec name'     }   } };  //!!!!!!!!!!!! Object.freeze(defaults);  //So we have an empty object with prototype set to our default object. var specificObject = Object.create(defaults);  // this will create new property Object.defineProperty(specificObject, 'sections',{     enumerable: true,     writable: true,     configurable: true,     value: {} }); console.log(specificObject.hasOwnProperty('sections')); //true  specificObject.sections['1'] = Object.create(defaults.sections['1']); 

explanation:

if you try to access obj.prop = val then javascript looks into obj's own properties, if not found then it looks into obj's prototype own properties. if found there then it /tries to assign val to/ lookup that property. if not found there then it tries to look into obj's prototype's prototype and so on. If prop is not found in the prototype tree then it creates new own property on obj and assigns val.

Therefore if prop is find on prototype and it is frozen you will get type error. Hope it brings some light.:)

EDIT:

as correctly pointed out by @KubaWyrostek specificObj.sections = {} will create new own property of specific Object, does not assign new value to the prototype's property, but it probably does the lookup for the property to check the writability, in that case it will run into frozen object. I didn't know about this before.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!