奇怪的行为与'使用严格'和只读属性

在MDN严格模式参考页面上说

在正常代码中静默失败的任何赋值(赋值给非可写属性,赋值给只有getter的属性,赋值给不可扩展对象上的新属性)都将引入严格模式

所以,使用他们的例子,像下面这样的事情会抛出一个TypeError

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

然而,我遇到了一个看起来“严格使用”的例子,对于这个规则有点太过分了。 这是我的设置

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'); 

运行node app.js给出

 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) 

有一些有趣的事情是关于这个输出有趣的。 首先是我们不试图在Object.prototype上设置lol属性,我们试图设置verboselol属性。 为了certificate这一点,我改变了definelol.js

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

现在,运行node app.js给出

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

第二件有意思的事情是,原来的程序在verbose.lol = '123'上失败了,但是开始制作sugar并且把它设置为123就非常开心。我不明白这一点,因为看起来我们创buildsugar的方式应该是简单的是我们创buildverbose的方式的语法糖

参见规范11.13.1部分:

在严格模式代码中发生分配时,其LeftHandSide不能评估为无法parsing的引用。 如果它在分配时引发ReferenceErrorexception。 LeftHandSide也可能不是对具有属性值{[[Writable]]:false}的数据属性的引用,对属性值为{[[Set]:undefined}的访问器属性,对于不存在的其[[Extensible]]内部属性值为false的对象的属性。 在这些情况下,会引发TypeErrorexception。

在您的示例代码中, =expression式的左侧实际上是对“数据”属性的引用,“可写”标志设置为false

现在我有些同情这个概念,它不应该适用于遗传属性,但我可以看到,可能会有强烈的反驳。 对象字面允许将属性创build为新的“糖”对象的“自己”属性,这看起来很奇怪。

编辑 – 为了清楚起见,这里的问题是赋值给一个对象属性总是关于赋值给对象的“自己”属性。 赋值不影响inheritance链的属性。 因此,所提出的问题涉及以下明显的矛盾:如果将“可写”标志设置为false的Object原型中的属性阻止对现有对象上的该属性名称的赋值,为什么赋值给该属性成功对象文字的评估?

这可能是一个很好的理由,或者它可能是一个错误。 无论是V8还是Firefox运行时目前所调用的(我猜也是这样),都是以相同的方式进行的。

你在每个对象的原型上定义了一个属性,所以他们在原型中都有一个'lol'属性。

糖是用他自己的“大声笑”来定义的,所以和原型中的“大声笑”没有任何关系。 那个是隐藏的

Verbose被定义为一个空的对象,因此,它将有一个“大声笑”属性可以通过它的原型。 因此, verbose.lol = ...不是创build一个新的属性,而是修改其原型的属性,当你声明它不可写时会引发一个错误。

如果你这样想的话,我认为这是有道理的。

编辑:这是不正确的方式看到它,阅读评论