我有以下JavaScript代码:
(function() {
function f(){ alert(1); }
return f();
function f(){ alert(2); }
})();
Run Code Online (Sandbox Code Playgroud)
你能解释为什么警报弹出2而不是1吗?
谢谢,
这将进入执行进入函数时发生的事情:抛出大量细节,处理所有函数声明(您使用过的样式),并且只有在此之后才会执行逐步执行代码.所以你的return陈述对选择哪个函数声明没有影响.并且所选择的声明始终是源代码顺序中的最后一个(这包括 - 在规范的第10.5节中非常粗糙的散文中).
如果使用函数表达式,结果将根本不同,函数表达式作为逐步代码的一部分进行评估:
(function() {
var f;
f = function(){ alert(1); };
return f();
f = function(){ alert(2); };
})();
Run Code Online (Sandbox Code Playgroud)
这段代码在技术上是不正确的(因为你return总是会遵循一个跟随的代码),但它说明了差异:你看到的是alert(1)发生而不是alert(2),因为这些表达式在达到之前不会被评估.
您可以在规范的10.4.3和10.5节中详细了解执行进入函数时所发生的事情(声明不是在第一步循序代码之前完成的唯一事情).
随着你的新知识,一个小测验:这里发生了什么?(注意:永远不要这样做.)
function foo() {
if (true) {
function bar() {
alert(1);
}
}
else {
function bar() {
alert(2);
}
}
bar();
}
foo();
Run Code Online (Sandbox Code Playgroud)
答案是:它有所不同,不要这样做.一些引擎将使用第一个bar,其他引擎将使用第二个,而其他引擎将其称为语法错误.这是因为这实际上是一个错误,因此引擎可以自由地做他们认为最好的事情.如果仔细查看语言语法,您会发现将函数声明放在其包含的直接范围内的分支中是无效的.它们必须处于该范围的顶层.通过对声明的新理解,原因应该是显而易见的:它们与范围内的执行流程无关,因此您无法根据执行流程选择它们.
那么现实世界会发生什么?可悲的是,如果你处于"松散"模式(不严格),通常不会出错.一些引擎(例如Chrome的V8,在撰写本文时)将忽略流控制语句,只选择最后声明的函数(因此你得到第二个 bar函数使用的反直觉结果),其他引擎(Firefox的SpiderMonkey, IE11的JScript)有效地重写您的代码,将这些声明转换为表达式,因此您获得第一个bar.例如,它会因引擎而异.好消息是,如果你在严格模式下尝试这个,那么所有这三个(V8,SpiderMonkey和IE11的JScript)都会失败而不是选择一个(V8和SpiderMonkey在控制台中有明确的错误消息; JScript只是令人惊讶的" bar未定义",但......).
如果你想要做的事就像上面,但有效和整个发动机保持一致,使用表达式:
function foo() {
var bar;
if (true) {
bar = function() {
alert(1);
};
}
else {
bar = function() {
alert(2);
};
}
bar();
}
foo();
Run Code Online (Sandbox Code Playgroud)
在kangax的Named Function Expressions Demystified页面上有一个有趣的探索.