On the MDN strict mode reference page it says
Any assignment that silently fails in normal code (assignment to a non-writable property, assignment to a getter-only property, assignment to a new property on a non-extensible object) will throw in 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 ran into an example where it seems 'use strict' is being a little overzealous about this rule. 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 couple of interesting things that are interesting about this output. First is that we are not trying to set the lol
property on Object.prototype
we are trying to set the lol
property of verbose
. To prove this I changed definelol.js
to be
Object.defineProperty(Object.prototype, 'lol', {
writable: true,
value: 'wat'
})
Now, running node app.js
gives
here 0
here 1
here 2
sugar.lol: 123
verbose.lol: 123
Object.prototype.lol: wat
The second thing that was interesting was that the original program failed on verbose.lol = '123'
but was perfectly happy creating sugar
and setting its lol
to 123. I don't understand this because it seems that the way we created sugar
should simply be syntactic sugar for the way we created verbose
See section 11.13.1 of the spec:
When an assignment occurs within strict mode code, its LeftHandSide must not evaluate to an unresolvable reference. If it does a ReferenceError exception is thrown upon assignment. The LeftHandSide also may not be a reference to a data property with the attribute value {[[Writable]]:false}, to an accessor property with the attribute value {[[Set]]:undefined}, nor to a non-existent property of an object whose [[Extensible]] internal property has the value false. In these cases a TypeError exception is thrown.
In your sample code, the left-hand side of an =
expression is, in fact, a reference to a data property with the "writable" flag set to false
.
Now I am somewhat sympathetic to the notion that it shouldn't apply to inherited properties, but I can see that there may be a strong counter-argument. That the object literal allows the property to be created as an "own" property of the new "sugar" object certainly seems odd.
edit — for clarity, the issue here is that assignment to an object property is always about assigning to an "own" property of the object. Assignments don't affect properties up the inheritance chain. Thus, the question posed involves the following apparent contradiction: if a property from the Object prototype with the "writable" flag set to false
prevents assignment to that property name on existing objects, why is it that assignment to that property succeeds in the course of evaluation of an object literal?
There could be a nice rationale for this, or it could be a bug. Both V8 and whatever the Firefox runtime is currently called (something-monkey I guess) act the same way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With