以下两个语句之间有什么区别(在全局窗口的上下文中)?
(function() { return a; } )(); // ReferenceError: a is not defined
(function(a) { return a; } )(); // returns undefined
我认为它与以下内容有关:
a; // ReferenceError: a is not defined
window.a; // undefined
似乎第二个函数在范围链上移动并在全局窗口范围结束,其中a
不是窗口的属性,因此返回undefined
。但是第一个函数不应该也这样做并返回undefined
吗?
我发现这个SO question关于未定义与未定义,但它似乎更多地应用于变量而不是窗口范围中的属性。
答案 0 :(得分:6)
我认为这是一个常见的陷阱和一个重要问题,如果您正在阅读此内容并任何不清楚,请在评论中告诉我。
a;
- 会抛出引用错误,因为它试图访问未定义的变量
function() { return a; } )();
- 这与上面的情况完全相同,它可以访问未定义的变量
object.a
- 将返回undefined,我们不是在这里尝试访问未定义的变量,而是已知对象的属性,这是不同的
(function(a) { return a; } )();
- 将返回undefined,a
是一个参数,而不是未定义的变量,它将被分配实际的语言原始值类型undefined
。
让我们深入挖掘一下吗?
让我们看看语言规范对所有这些案例的评价:
规范说明here:
如果是IsUnresolvableReference(V),则抛出 ReferenceError 异常。
规范声明:
IsUnresolvableReference(V)。如果基值未定义,则返回 true ,否则返回 false 。
这就是为什么会发生以下情况:
a; // ReferenceError: a is not defined
由于未定义基值,因此会根据规范指定引发引用错误。
在一个对象中,base不是未定义的(它是对象),所以它都很好并且不会抛出任何错误。这样解决了:
当V是具有基本基值的属性引用时,GetValue使用以下[[Get]]内部方法。使用base作为其值并使用属性P作为其参数调用它。采取以下步骤:
设O为ToObject(base)。
设desc是使用属性名P调用O的[[GetProperty]]内部方法的结果。
如果未定义desc,请返回 undefined 。
这就是你看到的原因:
window.a; // undefined
另一种情况 - 参数完全不同,参数存在,但其值设置为原始值类型undefined。现有的和未定义的并且不存在之间存在差异:)
如果n大于argCount,则让v为undefined,否则让v为args的第n个元素的值。
这就是原因:
(function(a) { return a; } )(); // returns undefined
答案 1 :(得分:1)
你真的过分思考你的第二个案例:(function(a) { return a; } )(); // returns undefined
是的,但它与此无关:
...向上移动范围链并在全局窗口范围结束,其中a不是窗口的属性,因此返回undefined
您为该函数定义了一个名为a
的参数。因为您没有提供值,所以它是undefined
。这真的很简单。