根据ES5.1规范,程序"use strict;" "foo".bar = 42;
导致创建一个String
对象,分配给它的属性,然后抛弃该对象,导致没有可观察到的影响 - 包括任何例外。 (可以通过在与Opera 12中的ES5兼容的JS实现中尝试来确认效果的缺失。)
在现代JS实现中,它会抛出TypeError
而不是尝试它:
"use strict"; "foo".bar = 42;
我很确定新行为是由ES6规范强制执行的,但是尽管多次阅读相关部分,但我无法看到指定TypeError
被抛出的位置。事实上,the key parts似乎没有改变:
6.2.3.2 PutValue( V , W )#
- ReturnIfAbrupt( V )。
- ReturnIfAbrupt( w ^ )。
- 如果Type( V )不是Reference,则抛出 ReferenceError 异常。
- 让 base 成为GetBase( V )。
- 如果IsUnresolvableReference( V )为真,那么
- ...
- 如果IsPropertyReference( V )为真,那么
- 一个。如果HasPrimitiveBase( V )为真,那么
- 我。断言:在这种情况下, base 永远不会为null或未定义。
- II。将 base 设置为ToObject( base )。
- 湾让成功? base 。[[Set]](GetReferencedName( V ), W ,GetThisValue( V ))。< / LI>
- ℃。 ReturnIfAbrupt(成功)。
- d。如果成功为false且IsStrictReference( V )为true,则抛出 TypeError 异常。
- 即回报率。
- ...
醇>
规范(ES6或更高版本)在哪里授权投掷TypeError
?
答案 0 :(得分:16)
我想它就在这里:
http://www.ecma-international.org/ecma-262/7.0/#sec-ordinaryset
9.1.9.1。普通集(O,P,V,接收器)
[...]
4.B。如果Type(Receiver)不是Object,则返回false。
(以前在[{3}}中称为[[Set]]。)
虽然PutValue
将base
提升为某个对象,但它与接收者的行为不同 - GetThisValue(V)
仍在原始V
上调用(原始基础)。因此,GetThisValue
返回一个原语,OrdinarySet.4b
无法分配新创建的ownDesc
并返回false
,这反过来导致PutValue.6d
抛出一个TypeError,如果参考是严格的。
V8的相应部分似乎遵循相同的逻辑:
Maybe<bool> Object::AddDataProperty(....
if (!it->GetReceiver()->IsJSReceiver()) {
return CannotCreateProperty(...
答案 1 :(得分:5)
@ georg的答案似乎是正确的ES6 +解释,但看起来这种行为也不是新的。来自ES5.1 PutValue:
- 醇>
如果是IsPropertyReference(V),那么
一个。如果HasPrimitiveBase(V)为false,那么让put为[base]的[[Put]]内部方法,否则让put为特殊[[Put]] 下面定义的内部方法。
湾使用base作为此值调用put internal方法,并为属性名称传递GetReferencedName(V),为值传递W, 投掷标志的和IsStrictReference(V)。
和引用的[[Put]]:
- 醇>
否则,这是在瞬态对象O
上创建自己的属性的请求一个。如果Throw为true,则抛出TypeError异常。
感觉我可能误读了某些东西......但是还有什么可以指出“这是在瞬态对象O上创建自己的属性的请求”指的是什么?