1

以下两个语句(在全局窗口的上下文中)有什么区别?

(function() { return a; } )(); // ReferenceError: a is not defined
(function(a) { return a; } )(); // returns undefined

我认为它与以下内容有关:

  a; // ReferenceError: a is not defined
  window.a; // undefined

似乎第二个函数沿着作用域链向上并在全局窗口作用域结束,其中a不是 window 的属性,因此返回undefined。但是第一个函数不应该也做同样的事情并返回undefined吗?

我发现这个关于未定义与未定义的问题,但它似乎更多地适用于变量而不是窗口范围内的属性。

4

2 回答 2

6

我认为这是一个常见的陷阱和一个重要的问题,如果您正在阅读本文并且有任何不清楚的地方,请在评论中告诉我。

简而言之

  • a;- 将抛出一个引用错误,因为它试图访问一个未定义的变量

  • function() { return a; } )();- 这与上面的情况完全一样,它是对未定义变量的访问

  • object.a- 将返回未定义,我们在这里不是试图访问未定义的变量,而是已知对象的属性,这是不同的

  • (function(a) { return a; } )();- 将返回未定义,a这里是一个参数而不是未定义变量,它将被分配实际的语言原始值类型undefined

让我们再深入一点好吗?

规格


让我们看看语言规范对所有这些情况的看法:

未声明的变量引用

规范在这里指出:

如果 IsUnresolvableReference(V),则抛出ReferenceError异常。

该规范指出:

IsUnresolvableReference(V)。如果基值未定义,则返回true ,否则返回false

这就是为什么会发生以下情况:

a; // ReferenceError: a is not defined

由于未定义基值,因此会引发规范指定的引用错误。

未声明的对象属性

在一个对象中,base 不是未定义的(它是对象),所以一切都很好并且不会引发错误。它是这样解决的:

当 V 是具有原始基值的属性引用时,GetValue 使用以下 [[Get]] 内部方法。使用 base 作为 this 值并使用属性 P 作为参数来调用它。采取以下步骤:

令 O 为 ToObject(base)。

令 desc 为使用属性名称 P 调用 O 的 [[GetProperty]] 内部方法的结果。

如果 desc 未定义,则返回undefined

这就是为什么你会看到:

window.a; // undefined

功能参数

另一种情况——参数则完全不同,参数存在,但其值设置为未定义的原始值类型。存在与未定义和不存在之间存在差异:)

这是在这里指定的

如果 n 大于 argCount,则令 v 未定义,否则令 v 为 args 的第 n 个元素的值。

这就是为什么:

(function(a) { return a; } )(); // returns undefined
于 2013-06-25T02:46:47.757 回答
1

你真的在想你的第二种情况:(function(a) { return a; } )(); // returns undefined

是的,但这与此无关:

... 上升到作用域链并在全局窗口作用域结束,其中 a 不是 window 的属性,因此返回 undefined

您为函数定义了一个名为 的参数a。因为您没有提供值,所以它是undefined. 真的就是这么简单。

于 2013-06-25T03:01:28.757 回答