奇怪的行为与'使用严格'和只读属性
在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
属性,我们试图设置verbose
的lol
属性。 为了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一个新的属性,而是修改其原型的属性,当你声明它不可写时会引发一个错误。
如果你这样想的话,我认为这是有道理的。
编辑:这是不正确的方式看到它,阅读评论