来自我的Chrome解释器:
a = 3; // OK, of course.
a.f = function() { return 4; }; // OK. To a number? Ok
a; // Prints 3
a.f(); // f is not a function.
a.f; // Undefined
当然,a
不是一个对象,我不能将新成员分配给不是对象的东西。但是,为什么解释器会吞下a.f
赋值,如果之后该方法或成员甚至不存在?
答案 0 :(得分:2)
如果您查看ECMA 5.1的8.7.2
,您会在底部看到此注释:
在上述方法之外无法访问可能在步骤1中创建的对象。实现可能会选择避免实际创建该临时对象。使用此内部方法的此类实际属性赋值可以具有可见效果的唯一情况是,它调用访问器函数或违反了Throw谓词错误检查。当Throw为true时,任何在瞬态对象上创建新属性的属性赋值都会引发错误。
第1步是Let O be ToObject(base).
如果查看ToObject()
中的9.9
方法,您会在表格中找到这两行:
创建一个新的Number对象,其[[PrimitiveValue]]内部属性设置为参数的值。有关数字对象的说明,请参见15.7。
结果是输入参数(无转换)。
因此,当您尝试在数字上设置函数时,它实际上正在发生(虽然作为一个noop),但由于在内部瞬态对象上发生了赋值,它在分配后变得无法访问。当你在常规对象上执行它时,它会返回实际对象,因此赋值是有意义的。
答案 1 :(得分:2)
没有一个很好的理由说明为什么它不被禁止,如果这就是语言开发时的实现方式,那就很容易了。
但为什么没有错误就实现了呢?因为它很好地反映了当您访问基元上的属性时发生的事情:它会隐式地转换为对象。无论您是使用属性引用进行赋值还是检索,都涉及到一个对象。即使被强制对象在之后立即被丢弃,分配仍将照常进行。
我们甚至可以看到,当我们在其原型上为该对象提供继承的访问器时:
"use strict";
Object.defineProperty(Number.prototype, "f", {
set: function(value) {
console.log(typeof this+" "+this+" got "+value+" assigned to .f");
},
get: function() {
console.log(typeof this+" "+this+"'s .f property was accessed");
return function() {
console.log("method called on "+typeof this+" "+this);
};
},
configurable: true
});
(3).f = "test value";
(3).f();