55

如何处理函数声明?

var abc = '';
if (1 === 0) {
  function a() {
    abc = 7;
  }
} else if ('a' === 'a') {
  function a() {
    abc = 19;
  }
} else if ('foo' === 'bar') {
  function a() {
    abc = 'foo';
  }
}
a();
document.write(abc); //writes "foo" even though 'foo' !== 'bar'

此示例在 Chrome 和 Firefox 中产生不同的输出。Chrome 输出foo,而 FF 输出19

4

4 回答 4

71

当被问到这个问题时,ECMAScript 5 (ES5) 很流行。在 ES5 的严格模式下,函数声明不能​​嵌套在if块内,如问题所示。在非严格模式下,结果是不可预测的。不同的浏览器和引擎实现了自己的规则来处理块内的函数声明。

截至 2018 年,许多浏览器都支持 ECMAScript 2015 (ES2015),以至于现在允许在 blocks 中声明函数。在 ES2015 环境中,块内的函数声明将被限定在该块内。问题中的代码将导致未定义函数错误,因为该函数a仅在语句范围内if声明,因此不存在于全局范围内。

如果你需要有条件地定义一个函数,那么你应该使用函数表达式

于 2012-04-09T05:51:06.213 回答
7

来自http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

在 javascript 中,你有函数声明:

function foo() {
}

和函数表达式

var foo = function() {
}

引自http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

“函数声明和函数变量总是被 JavaScript 解释器移动('提升')到其 JavaScript 范围的顶部”。

因此,在您的第一个示例中发生的情况是 , 的函数声明function a()被提升到 Javascript 范围的顶部,因此即使 if 评估为 false 也会产生 'foo'

var foo其视为普通的 Javascript 语句,它仅在您的 javascript 运行时执行,与 不同function foo(),这就是以下有效的原因:

alert(foo());

function foo() {
   return 'gw ganteng';
}

在这里,function foo()由解析器解析,放入foo()当前范围,然后尝试调用alert(foo())

http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

在 JavaScript 执行中,有 Context(ECMA 5 将其分为 LexicalEnvironment、VariableEnvironment 和 ThisBinding)和 Process(按顺序调用的一组语句)。进入执行范围时,声明有助于变量环境。它们与声明(例如退货)不同,不受其流程规则的约束。

于 2012-04-09T05:29:02.247 回答
2

ECMA-262 v5 要求实现在进入任何新的全局或函数级执行上下文时在第一次传递期间注册所有函数和变量声明。Chrome 在技术上就是在这里做的,因为它在执行之前查看elseandthen块并注册。a()不幸的是,它会产生最难以理解的结果。

FF 在评估 if 语句并将函数和变量声明添加到当前上下文之前一直等到它评估。顺便提一句。两种浏览器都在 catch 和 finally 子句中这样做。

这实际上只是两个不同的 ECMA 实现处理一个不应该开始存在的特性的问题。手头的场景说明了为什么函数声明不应该在控制流语句中。

于 2013-12-11T23:42:16.930 回答
0

函数声明不能​​在{}块外访问。

if (true) {
  function sayHi() {
    alert("hii");
  }
  sayHi(); //accessible
}

sayHi(); //error, not accessible since out of the block

如果要定义条件函数,请使用函数表达式,例如

let sayHi;
if (true) {
  sayHi = function(){
    alert("hii");
  }
  sayHi(); //accessible
}

sayHi(); //accessible
于 2021-02-05T02:50:22.063 回答