需要了解Javascript函数提升示例

Sid*_*yas 23 javascript function hoisting

我读了Javascript Hoisting的概念.它让我感到很困惑,但是我看到了一些例子,并且知道吊装实际上是做什么的.

所以基本上" 提升是JavaScript将所有声明移动到当前范围顶部(到当前脚本或当前函数的顶部)的默认行为. "

但我无法理解以下实施:

var is_android = true;
if (is_android) {
    function foo() {
        alert('I am Android');
    }
} else {
    function foo() {
        alert('I am NOT Android');
    }
}
foo();
Run Code Online (Sandbox Code Playgroud)

输出在警告框中显示" 我不是Android ".

我想知道为什么foo()从else块调用,即使is_android值为true.

任何帮助将不胜感激.

Fel*_*ing 21

tl; dr:不要在块中使用看起来像函数声明的东西,尤其不是条件.


事实上,大多数浏览器都以错误的方式解释这段代码.他们把函数定义为函数声明,即使函数声明不准里面块,因为一个函数声明不是一个声明,这是一个源元素.

这一般如何工作:

在代码执行之前,解释器会查找所有变量和函数声明,而不管它们在何处,并在当前/新环境中为它们创建绑定.然后它开始实际执行代码.

因此,假设函数定义被解释为声明,因为有两个声明,最后一个声明获胜.您的代码基本上变为:

function foo() {
    alert('I am Android');
}
function foo() {
    alert('I am NOT Android');
}
var is_android;

is_android = true;
if (is_android) {

} else {

}
foo();
Run Code Online (Sandbox Code Playgroud)

其他引擎会以不同的方式解释它,但仍然不正确(IMO,见下文):

在以下脚本中,零函数永远不会被定义,也不能被调用,因为'if(0)'将其条件评估为false:

if (0) {
   function zero() {
      document.writeln("This is zero.");
   }
}
Run Code Online (Sandbox Code Playgroud)

注意:某些JavaScript引擎(不包括SpiderMonkey)错误地将任何函数表达式视为函数定义.即使使用always-false if条件,这也会导致零被定义.有条件地定义函数的更安全的方法是匿名定义函数并将其分配给变量:

if (0) {
   var zero = function() {
      document.writeln("This is zero.");
   }
}
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,如果函数定义真正被解释为函数表达式(类似于(function zero() { ... })),那么函数的名称将无法在包含范围内访问,并且函数将丢失.

  • @thefourtheye:变量声明本身也被提升,只是赋值发生在代码中.总的来说,它比这更复杂,我更新了我的答案. (3认同)

650*_*502 5

在Javascript中,两个相似的外观之间存在细微差别

 function square(x) { return x*x; }
Run Code Online (Sandbox Code Playgroud)

 var square = function(x) { return x*x; }
Run Code Online (Sandbox Code Playgroud)

最大的区别在于,在第一种情况下,将函数对象分配给square名称是在进入范围时完成的,而不是在到达该行时.这允许调用稍后在源代码中定义的函数...例如:

console.log(cube(12));
function cube(x) { return x*x*x; }
Run Code Online (Sandbox Code Playgroud)

是一个有效的脚本,即使调用发生在函数定义"之前"(顺便说一下,允许这种代码是IMO规则在语言中的原因),它也会起作用.

在第二种情况下,赋值只是一个常规语句,并且当控制流通过它时(和如果)执行它.

如果您希望该代码段按预期工作,则只需更改代码即可

function <name> (...) { ... }
Run Code Online (Sandbox Code Playgroud)

var <name> = function (...) { ... }
Run Code Online (Sandbox Code Playgroud)

PS:您也可以在第二种形式中重复该名称,但通常不会这样做,而是使用匿名函数.