Javascript命名的函数定义在不应该执行时执行

时间:2013-06-05 02:54:38

标签: javascript

我不知道这里发生了什么。代码是:

  if( true ) { 

      console.log('In first function definition');

      function test(){
        console.log('Hello world');
      }

    } else {

      console.log('In the second function definition');

      function test(){
        console.log('Goodbye world');
      }

    }

  test();

我希望这会登录控制台:

'In the first function definition'
'Hello world'

但相反它记录:

'In the first function definition'
'Goodbye world'

当代码没有进入该分支时,如何创建第二个命名函数?

5 个答案:

答案 0 :(得分:10)

请记住,JavaScript中的所有内容都是功能范围的;没有块范围。

为此,您在相同的范围内定义了两个函数声明(无论if-else所在的范围),具有相同的名称,在不同的块中。这会在浏览器之间产生不一致的结果。

您需要为这些函数指定不同的名称,或使用函数表达式,如下所示:

var f;
if(true) { 
   console.log('In first function definition');

   f = function(){
     console.log('Hello world');
   };

} else {
  console.log('In the second function definition');

  f = function(){
    console.log('Goodbye world');
  };
}
f();

对你的优秀问题

  

但是如果我们不输入代码的那个分支,那么函数是如何定义的?如果没有执行该块,为什么范围需要考虑?

简单的答案是功能声明在范围内“悬挂”,立即可用任何地方,甚至在声明本身之前。

即:

function foo(){
    f(); //perfectly valid

    function f(){
    }
}

更长的答案是,在进入范围之前,所有变量声明和函数声明都被删除,并放在“激活对象”上。然后将激活对象放置在“范围链”的头部。执行该函数时,可以从那里简单地解析对这些变量和函数的任何引用。

答案 1 :(得分:2)

javascript中的函数定义独立于控制结构,这意味着当你第二次重新定义函数时,即使它位于控件结构的一个分支中,它永远不会点击它仍然重新定义函数。无论如何你还想做什么?

答案 2 :(得分:1)

Some JavaScript engines treat the definition as always occurring regardless of the condition,第二个定义将覆盖第一个定义。

  

注意:某些JavaScript引擎(不包括SpiderMonkey)错误地将任何函数表达式视为函数定义。

答案 3 :(得分:1)

要添加到Adam's answer,您可以在分配功能时找到解决方法。

if( true ) { 
  console.log('In first function definition');
  test = function() { console.log('Hello world'); }
} else {
  console.log('In the second function definition');
  test = function(){ console.log('Goodbye world'); }
}
test();

这将打印

  

在第一个功能定义中   你好世界

答案 4 :(得分:0)

根据ECMA-262,在执行任何代码之前处理函数声明。因此,在任何地方声明函数都可以有效地将它们“移动”(“提升”)到执行上下文的顶部。

但是,并非所有看起来像声明的声明都是声明。在以下内容中:

if (false) {
  function fred() {return true;}
}

有些浏览器会看到函数声明:

alert(fred());

显示“true”。其他浏览器使用ECMA-262的扩展,允许将其视为命名函数表达式函数语句(我将尝试查找Richard Cornford对comp的优秀帖子的引用.lang.javascript关于那个见下文),以便:

alert(fred());

抛出 fred 未定义的错误。在Firefox和IE中试用。

所以底线是如果你想有条件地创建一个函数,使用一个明确的函数表达式。它们通常与特征测试结合使用,例如创建一个函数来获取元素的textContent或innerText:

var getText = (function() {
  var el = document.createElement('div');

  if (typeof div.textContent == 'string') { 
    div = null;
    return function(el) {return el.textContent;};

  } else if (typeof div.innerText == 'string') { 
    div = null;
    return function(el) {return el.innerText;};
  }
}());

修改

这是Richard Cornford在FunctionExpression's and memory consumptions的帖子。重要的部分:

  

实际上它是一个函数声明;语法扩展名是   能够允许有条件地创建函数,因为   作为一个声明,它可以在一个块内进行评估。

但整篇文章值得一读。

另请注意,函数语句为warned against in ES5 strict mode,可能会在ECMAScript的某个未来版本中引入。