在初始化和调用之间重新定义函数

时间:2015-07-30 19:13:45

标签: javascript

为什么此警告Initial而不是Redefined

var inner = function() { alert('Initial'); }
var outer = function() {
    setTimeout(function() { 
       inner = function() { alert('Redefined'); }
    }, 0);
    return inner;
}
var f = outer();
setTimeout(f, 1000);

2 个答案:

答案 0 :(得分:2)

将超时设置为零并不 意味着将立即运行回调。控制立即进入下一行,返回inner。此时尚未重新定义且f指向旧inner,这就是您看到" Initial"的原因。

将您的代码更改为以下内容:

var inner = function() { console.log('Initial'); }
var outer = function() {
    setTimeout(function() { 
       inner = function() { console.log('Redefined'); }
    }, 0);
    return inner;
}
outer();
setTimeout(function() { 
    inner(); 
}, 1000);

现在您将看到"重新定义",因为我们会调用outer,它将在未来的某个时刻重新定义inner。当我们在超时处理程序中调用inner()时,它指向重新定义的版本,因此它将打印"重新定义"。

你可能想知道我们为什么不能这样做:

var inner = function() { console.log('Initial'); }
var outer = function() {
    setTimeout(function() { 
       inner = function() { console.log('Redefined'); }
    }, 0);
    return inner;
}
outer();
setTimeout(inner, 1000);

但是你会得到" Initial"这也是出于同样的原因;调用setTimeoutinner仍然指向原始版本。

答案 1 :(得分:0)

这是因为inner的值是在执行所有其他JS之后设置的。该函数被发送到其他堆栈并从main堆栈中删除。即使您将计时器设置为 0 ms ;当所有其他JS执行时,将执行setTimeout函数。以下是您的程序执行方式:

  1. 初始化innerouter
  2. 执行outer并使用返回值初始化f
  3. outer()如何执行?方法如下:

    1. 点击setTimeout Web API,其具有应在0 ms后执行的功能,但它将被发送到事件循环,并将在稍后执行。其余的代码将被执行。
    2. 点击return声明。它将访问inner的值。现在,请记住您的setTimeout函数尚未执行。因此,该函数将移动到原型链并找到inner。由innerGlobal上下文中定义。该值将被退回。

    3. 最后,outer()将函数返回到f,由另一个setTimeout执行。 setTimeout中的功能也会发送到事件循环

    4. 现在,事件循环有两个要调用的函数!其中一个将重置内部值,另一个将提醒“初始”,但inner的值将立即更改。警报将在定义的1秒后显示。