为什么功能在' if'中定义。条件的表达部分在外面不可见?

时间:2014-03-31 14:14:49

标签: javascript

if (function f() {}) {
    console.log(f) // Throw an error: f is not defined
}

为什么日志会导致错误,f已经在上面的表达式中定义了?


您希望这相当于:

function f () {}
if (true) {
    console.log(f); // Throw an error: f is not defined
}

4 个答案:

答案 0 :(得分:14)

当你说

function f () {}

这是一个函数声明语句。此功能将在封闭环境中定义。因此,如果它是在另一个函数中定义的,那么该函数将在该环境中定义,您可以通过名称访问该函数。

但是,当你在表达式中使用函数声明时,它不会被视为函数声明,而是函数表达式,它将被这样评估(从ECMA Script 5.1 Standard Specification引用)

  

13 Function Definition: Semantics

     

制作

     

FunctionExpression:

 function Identifier ( FormalParameterListopt ) { FunctionBody }
     

评估如下:

     
      
  1. funcEnv成为调用NewDeclarativeEnvironment 传递正在运行的执行上下文Lexical Environment作为参数的结果
  2.   
  3. 让envRec成为funcEnv的环境记录。
  4.   
  5. 调用envRec的 CreateImmutableBinding(N)具体方法,将Stringier的String值作为参数。
  6.   
  7. 让闭包是创建一个新的Function对象的结果,该对象在13.2中指定,其中参数由FormalParameterListopt指定,而body由FunctionBody指定。传入funcEnv作为范围。如果FunctionExpression包含在strict code中或者其FunctionBody是严格代码,则将true作为Strict标记传递。
  8.   
  9. 调用envRec的 InitializeImmutableBinding(N,V)具体方法,将Identifier的String值和闭包作为参数传递。
  10.   
  11. 返回封闭。
  12.   

因此,当您在表达式中创建函数时,

  1. 将创建一个新的环境上下文(参见第一项)

  2. 函数的名称将绑定到新创建的环境(参见第三项)。

  3. 函数体将用于创建实际的函数对象(参见第四项)

  4. 创建的实际函数对象绑定到新创建的上下文中的函数名称(参见第五项)

  5. 然后返回函数对象。

  6. 由程序将函数对象分配给当前环境上下文中的变量以保留该函数。否则,当表达式评估完成时,新创建的环境上下文变为无效。因此,函数f将无法在外部显示。

答案 1 :(得分:7)

您的假设不正确。这两个片段并不相同。第一个是named function expression,您不存储值(实际的函数对象)。这样的对象总是真实的 - 因此if得到了执行。

这些函数的函数名是(或者应该)只在函数本身 中可见(除了一些早期的IE版本)。因此,由于f根本不存在,因此当您尝试将ReferenceError传递给console.log时会引发{{1}}。

答案 2 :(得分:4)

函数声明语句在其周围范围内定义函数,甚至将定义移到顶部。但是,这是一个命名的函数表达式。该函数由其内部的名称定义,但不在外部定义(旧的IE除外,它是一个错误)。除此之外,它只是一个设置了名称的函数。仅当语句以关键字function开头时,它才算作函数语句。

这有效:

function f(){};
if (f) console.log(f);

答案 3 :(得分:3)

if (function f() {}) {
    console.log(f) // Throw an error: f is not defined
}

函数声明被视为函数表达式(如function(){}),而不是函数语句。

证明:

if (function f(x) {return x}(1)) {
    console.log('foo'); //Will log
}

if (function f(x) {return x}(false)) {
    console.log('foo'); //Will not log
}

如果你的函数只是一个语句,你就不能立即执行它(不用括号括起来,或者用!作为前缀,把它变成表达式)。

function f(x) {return x}(false) //Would yield a syntax error