我不知道这里发生了什么。代码是:
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'
当代码没有进入该分支时,如何创建第二个命名函数?
答案 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的某个未来版本中引入。