5

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

  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'

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

4

5 回答 5

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();

对于你的优秀问题

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

简单的答案是函数声明是“提升的”,并且在范围内的任何地方都可以立即使用,甚至在声明本身之前。

IE:

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

    function f(){
    }
}

更长的答案是,在进入作用域之前,所有变量声明和函数声明都被剥离出来,并放在“激活对象”上。然后将激活对象放置在“作用域链”的头部。当您执行该函数时,对这些变量和函数的任何引用都会从那里简单地解析。

于 2013-06-05T02:56:06.710 回答
2

javascript 中的函数定义独立于控制结构,这意味着当您第二次重新定义函数时,即使它位于永远不会命中它的控制结构的分支中,仍然会重新定义函数。你到底想做什么?

于 2013-06-05T02:57:30.500 回答
1

一些 JavaScript 引擎将定义视为总是发生而不管 condition,第二个定义会覆盖第一个定义。

注意:一些 JavaScript 引擎,不包括 SpiderMonkey,错误地将任何具有名称的函数表达式视为函数定义。

于 2013-06-05T02:58:52.490 回答
1

要添加到亚当的答案,如果您分配功能,您可以绕过它。

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();

这将打印

在第一个函数定义
Hello world

于 2013-06-05T03:01:55.427 回答
0

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

但是,并非所有看起来像声明的东西都是声明。在下面的:

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

一些浏览器会看到一个函数声明,所以:

alert(fred());

显示“真实”。其他浏览器使用 ECMA-262 的扩展,允许将其视为命名函数表达式函数语句(我将尝试找到对 Richard Cornford 在 comp.lang.javascript 上关于该内容的出色帖子的引用,见下文),以便:

alert(fred());

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

So the bottom line is if you want to conditionally create a function, use an unambiguous function expression. They're often used in conjunction with feature testing, e.g. to create a function to get the textContent or innerText of an element:

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;};
  }
}());

Edit

Here's Richard Cornford's post in FunctionExpression's and memory consumptions. The important part:

In fact it is a function statement; a syntax extension that is capable of allowing the conditional creation of a function because being a Statement it can be evaluative inside a block.

But the whole post is worth reading.

Also note that function statements are warned against in ES5 strict mode and may be introduced in some future version of ECMAScript.

于 2013-06-05T03:19:51.837 回答