4

考虑以下代码。

<!DOCTYPE html>
<script>
  console.log(a);
  function a() {}
</script>

请注意,a它似乎在定义之前已被访问。控制台输出是:(jsfiddle

function a() {}

函数和变量名称是在任何其他代码运行之前定义的,因此 console.log 调用在这里起作用。这称为吊装

但是如果函数被定义为函数调用中的参数,这不起作用。看看这段代码。

<!DOCTYPE html>
<script>
  function a() {}
  a(function b() {});
  console.log(b);
</script>

请注意,该函数b是在对a. 不是在闭包内部,而是在调用内部。控制台输出是:(jsfiddle

Uncaught ReferenceError: b is not defined

我想知道为什么会这样。这是预期的行为吗?这发生在 Chrome 和 Firefox 中。

更新:这个jsfiddle显示函数表达式中的名称在定义它们的范围内永远不可用。但是,名称是在函数本身的范围内定义的。这意味着命名函数表达式可以引用名称,但只能在函数内部。该名称也存储在函数的name参数中。

<!DOCTYPE html>
<script>
  console.log(a); // undefined
  var a = function b() {
    console.log(b); // function b() { … };
  };
  a(); // function b() { … };
  console.log(a); // function b() { … };
  console.log(a.name); // b
  console.log(b); // Uncaught ReferenceError: b is not defined
</script>
4

3 回答 3

3

在内部a(function b() {});,函数是函数表达式,而不是函数声明(仅被提升)。你可以看看var functionName = function() {} vs function functionName() {}的区别。

于 2013-01-08T15:50:15.567 回答
3

EcmaScript §13 (参见NOTE下方的段落)定义了如何处理函数表达式和函数声明。

函数声明在 EnvironmentRecord 构建(§10.5)时被实例化,因此被提升,函数表达式稍后被评估,它的可选标识符对封闭范围是不可见的。

由于这是一个函数表达式,因此它的名称对外部范围不可见。是一样的

a = function(){};  // valid as it is a function expression

a = function b(){};// also valid

// b is is not accessable here, same as the anonymous function, but a of course is.

两者都是有效的,但 b 对外部范围不可见。但是,在函数声明中省略名称是无效的。
函数表达式的可选标识符用于函数体内的引用目的(例如,启用递归调用)。

更新您的更新:

第一个 console.log 产生 undefined 而不是抛出错误的原因是提升(当实例化被提升时,初始化不是):

  console.log(a); // undefined
  var a = function b() {};
  console.log(a); // function b() {}

  // equals (hoisted):
  var a;
  console.log(a); // undefined
  a = function b() {};
  console.log(a); // function b() {}
于 2013-01-08T15:51:20.220 回答
0

function b()a(function b() {});在调用执行之前不存在。

这样,JS 不会在代码中搜索函数。另外,function b() {}不是函数声明,您只是将其作为参数传递。访问该功能的唯一方法是在function a()

function a() {console.log(arguments[0])}
a(function b() {});
//function b() {}

但是,这并不意味着您可以实际调用b()inside a(),因为b()它是在函数调用的范围内定义的a,而不是在函数本身中。基本上,这个名字b是没有用的。

于 2013-01-08T15:49:09.233 回答