6

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

任何在正常代码中静默失败的赋值(赋值给不可写属性、赋值给 getter-only 属性、赋值给不可扩展对象的新属性)都将进入严格模式

因此,使用他们的示例,执行以下操作会引发 TypeError

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

然而,我遇到了一个例子,似乎“使用严格”对这条规则有点过分热心。这是我的设置

定义lol.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);

应用程序.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)

这个输出有几个有趣的地方。首先是我们不是在尝试设置lol属性,Object.prototype而是在尝试设置 的lol属性verbose。为了证明这一点,我变成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并将其设置lol为 123。我不明白这一点,因为似乎我们创建的方式sugar应该只是我们创建方式的语法糖verbose

4

2 回答 2

3

请参阅规范的第 11.13.1 节:

当在严格模式代码中发生赋值时,其 LeftHandSide 不得评估为不可解析的引用。如果确实如此,则在分配时会引发 ReferenceError 异常。LeftHandSide 也可能不是对具有属性值 {[[Writable]]:false} 的数据属性的引用,对具有属性值 {[[Set]]:undefined} 的访问器属性的引用,也不是对不存在的[[Extensible]] 内部属性值为 false 的对象的属性。在这些情况下,会引发 TypeError 异常。

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

现在我有点同情它不应该适用于继承属性的概念,但我可以看到可能存在强烈的反驳。对象字面量允许将属性创建为新的“糖”对象的“自己的”属性,这当然看起来很奇怪。

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

这可能有一个很好的理由,或者它可能是一个错误。V8 和目前称为 Firefox 运行时的任何东西(我猜是猴子)都以相同的方式运行。

于 2014-10-09T22:36:32.573 回答
0

您在每个对象的原型上定义了一个属性,因此它们的原型中都有一个“lol”属性。

Sugar 是用他自己的“lol”定义的,因此这与原型中的“lol”无关。那个是隐藏的。

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

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

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

于 2014-10-09T22:56:42.657 回答