请考虑以下代码段:
function myFunction(a){
console.log(a);
}
myFunction(1);
//1
var oldFunction = myFunction;
function myFunction(b){
console.log('intercept');
oldFunction(b);
}
myFunction(1);
//too many calls, console outputs intercept indefinitely
代码无法正常工作并无限期地输出“拦截”。然后我搜索了Stack Overflow,我发现以下修改后的code按预期工作:
function myFunction(a){
console.log(a);
}
myFunction(1);//1
var oldFunction = myFunction;
var myFunction = function(b){
console.log('intercept');
oldFunction(b);
}
myFunction(1);
//intercept
//1
我的问题是:为什么第一个代码没有按预期工作?我知道函数声明和函数表达式之间存在差异(主要是由于提升行为),但我仍然感到困惑。
编辑:确实是一种被误解的吊装行为。我意识到如果我执行下面的第一个代码是有效的:eval(`function myFunction(a){
console.log(a);
}
myFunction(1);
//1
var oldFunction = myFunction;`);
eval(`function myFunction(b){
console.log('intercept');
oldFunction(b);
}
myFunction(1);`);
//1
//intercept
//1
这就结束了这个问题。当我单独执行代码时,会清楚地知道函数myFunction正在提升。
答案 0 :(得分:3)
这是因为吊装。在JavaScript中,function declarations are hoisted意味着它们被“提升”到顶部并首先声明,并且可以在它们被定义之前使用:
foo(); //logs "in foo"
function foo() {
console.log("in foo");
}
另一方面,函数表达式不像函数声明那样被提升。 var
is still hoisted但它的值(匿名函数)没有给变量。为了使其更清晰,您的第一个片段基本上看起来像这样(在函数声明和var
之后被提升):
var oldFunction;
function myFunction(a) {
console.log(a);
}
function myFunction(b) {
console.log('intercept');
oldFunction(b);
}
//myFunction(1);
oldFunction = myFunction;
myFunction(1);
(旁注:我已经注释掉了第一个引发错误的调用,因为当你第一次尝试执行oldFunction
时myFunction
未定义。上面的代码片段重现了你的内容在问题的第一个片段中描述
因此,在您的代码中,第一个不起作用因为您有两个相同名称的函数。因此,第一个myFunction
被覆盖,现在它引用了更新的函数。这将导致代码在函数调用自身时递归,使其无限期运行。
在你的第二个例子中,基本上是这样的:
var oldFunction;
var myFunction;
function myFunction(a) {
console.log(a);
}
//myFunction(1);
oldFunction = myFunction;
myFunction = function(b) {
console.log('intercept');
oldFunction(b);
}
myFunction(1);
在功能提升中,整个声明被提升,而不仅仅是var
之类的名称。所以在第二个例子中,当你第一次调用它时,第一个函数是 not 被覆盖。然后,当您执行oldFunction = myFunction
时,您为oldFunction
分配了对myFunction
的引用,这是旧函数。执行它将执行旧功能。这将记录:
intercept
1
正如预期的那样,永远不会递归。
答案 1 :(得分:1)
只有这部分有效:
function myFunction(a){
console.log(a);
}
myFunction(1);
//1
一旦你添加剩下的......
function myFunction(a){
console.log(a);
}
myFunction(1);
//1
var oldFunction = myFunction;
function myFunction(b){
console.log('intercept');
oldFunction(b);
}
myFunction(1);
//too many calls, console outputs intercept indefinitely
它会失败,因为它对JS引擎的读取方式如下:(按照这个顺序)
var myFunction, oldFunction;
myFunction = function(a){
console.log(a);
}
//immediately overwriting myFunction by
myFunction = function (b){
console.log('intercept');
oldFunction(b);
}
myFunction(1); //this already fails, because `oldFunction` is undefined and therefore can't be called
oldFunction = myFunction;
myFunction(1); //too many calls, console outputs intercept indefinitely
由于提升,在你的代码中这个功能
function myFunction(a){
console.log(a);
}
完全消除并立即替换为
function myFunction(b){
console.log('intercept');
oldFunction(b);
}
甚至在代码中执行单个表达式之前。像var oldFunction = myFunction
答案 2 :(得分:0)
首先,示例oldFunction
定义为
function myFunction(b){
console.log('intercept');
oldFunction(b); // calls `oldFunction` again
}
第二个示例oldFunction
的定义为
function myFunction(a){
console.log(a);
}
答案 3 :(得分:0)
在第一个代码片段中,myFunction被新的myFunction覆盖,以及oldFunction引用相同的代码,因此代码以递归顺序执行。但是在第二个代码中,第二个代码myFunction声明为无法覆盖旧myFunction的函数,当oldFunction被调用时,它仅指向第一个myFunction。