Strange behavior using "strict" and read-only properties

MDN strict mode help page says

Any assignment that, without speculative failure in the normal code (assignment to an unprivileged property, assignment to a property only for a getter, assignment to a new property on a non-extensible object) will cause strict mode

So, using their example, doing something like the following, throws a TypeError

"use strict"; var obj1 = {}; Object.defineProperty(obj1, "x", { value: 42, writable: false }); obj1.x = 9; // throws a TypeError 

However, I came across an example where, it seems, "use strict" overestimates this rule a bit. Here is my setup

definelol.js

 Object.defineProperty(Object.prototype, 'lol', { value: 'wat' }) 

setlol.js

 'use strict'; console.log('here 0'); var sugar = { lol: '123' } console.log('here 1'); var verbose = {}; verbose.lol = '123'; console.log('here 2'); console.log('sugar.lol:', sugar.lol); console.log('verbose.lol:', verbose.lol); console.log('Object.prototype.lol:', Object.prototype.lol); 

app.js

 require('./definelol.js'); require('./setlol.js'); 

running node app.js gives

 here 0 here 1 /pathto/setlol.js:10 verbose.lol = '123'; ^ TypeError: Cannot assign to read only property 'lol' of #<Object> at Object.<anonymous> (/pathto/setlol.js:10:13) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.require (module.js:364:17) at require (module.js:380:17) at Object.<anonymous> (/pathto/app.js:2:1) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) 

There are a few interesting things that are interesting in this release. First, we are not trying to set the lol property to Object.prototype , we are trying to set the lol verbose property. To prove this, I changed definelol.js to

 Object.defineProperty(Object.prototype, 'lol', { writable: true, value: 'wat' }) 

Now starting node app.js gives

 here 0 here 1 here 2 sugar.lol: 123 verbose.lol: 123 Object.prototype.lol: wat 

The second interesting thing was that the original program did not work on verbose.lol = '123' , but was quite happy to create sugar and set its lol to 123. I do not understand this, because it seems that we created sugar should be just syntactic sugar for how we created verbose

+6
source share
2 answers

See specification section 11.13.1:

When assignment occurs in strict mode code, its LeftHandSide should not evaluate an unsolvable link. If an assignment throws a ReferenceError exception. LeftHandSide may also not refer to a data property with the attribute value {[[[Writable]]: false}, to an accessor property with the attribute value {[[Set]]: undefined}, a stable property of an object whose internal property is [[Extensible]] is false. In these cases, a TypeError exception is thrown.

In your code example, the left side of the = expression is, in fact, a reference to a data property with a writable flag set to false .

Now I sympathize somewhat with the fact that it should not be applied to inherited properties, but I see that there can be a strong counterargument. The fact that an object literal allows you to create a property as the "own" property of a new "sugar" certainly seems strange.

edit - for clarity, the problem is that the assignment to the object is always associated with the assignment of the "own" property of the object. Assignments do not affect properties in the inheritance chain. Thus, the question posed includes the following obvious contradiction: if the property of the Object prototype with the "writeable" flag set to false prevents the assignment of this property name to existing objects, why does this assignment succeed in the course of evaluating an object literal?

There may be a good explanation, or it could be a mistake. Both V8 and what is currently called the Firefox runtime (something like a monkey) work the same way.

+3
source

You defined the property on the prototypes of all the objects, so they all have the "lol" property in their prototype .

Sugar is defined by its own β€œlol,” so it has nothing to do with the β€œlol,” which is in its prototype. This one is hidden.

Verbose is defined as an empty object, so it will have the lol property, accessible through its prototype. Therefore, verbose.lol = ... does not create a new property, but modifies its prototype property, which causes an error because you stated that it is not writable.

I think everything makes sense if you think so.

EDIT: this is the wrong way to see this, read the comments

0
source

Source: https://habr.com/ru/post/976532/


All Articles