函数对象上的javascript闭包

时间:2018-06-11 07:56:46

标签: javascript closures

为什么关闭行为不会在这里发挥作用:



function init(){
  for (var i = 1; i <= 2; i++) {
  
  function timer() {
    var k=i;
    console.log("in timer");
    console.log(timer.i);
    console.log(k);
  }
  
  timer.i = i;
  setTimeout(timer, 0);
  
  }
}
&#13;
<body onload="init()";>
</body>
&#13;
&#13;
&#13;

为什么timer.i没有在外部函数init的堆栈中取i的最后一个值?但是,它确实需要k的外部。

2 个答案:

答案 0 :(得分:0)

EcmaScript 6中的函数声明现在是块作用域的,就像let声明一样(与let的区别在于变量在外部global / functionnal范围内声明)。

您的代码全局等同于

&#13;
&#13;
for (var i = 1; i <= 2; i++) {
  let timer = function() {
    console.log("in timer");
    console.log(timer.i);
  }
  timer.i = i;
  setTimeout(timer, 1000);
}
&#13;
&#13;
&#13;

这意味着您有不同的timer值。

请注意,如果您使用的是var而不是let而不是函数声明,那么获得两倍的相同日志。

好读:http://2ality.com/2015/02/es6-scoping.html

请注意,为函数添加属性并不是一个好习惯。您应该使用范围变量,例如:

for (var i = 1; i <= 2; i++) {
  let timer_i = i;
  setTimeout(function timer(){
    console.log("in timer");
    console.log(timer_i);
  }, 1000);
}

在这个简单的情况下可以写成

for (let i = 1; i <= 2; i++) {
  setTimeout(function timer(){
    console.log("in timer");
    console.log(i);
  }, 1000);
}

答案 1 :(得分:0)

实际上有两个 timer。当解释器在类似循环内的函数声明中运行时,它将覆盖外部作用域中的前一个函数名称(如果存在这样的函数)。这个片段可能会更清晰:

&#13;
&#13;
for (var i = 1; i <= 2; i++) {
  const oldTimer = window.timer;
  function timer() {
    console.log("in timer");
    console.log(timer.i);
  }
  timer.i = i;
  console.log('oldTimer is ' + oldTimer + (oldTimer ? ' with i of ' + oldTimer.i : ''));
  console.log('is oldTimer the same as the new timer? ' + (oldTimer === timer));
  setTimeout(timer, 1000);
}
console.log('Outside of for loop: timer is ' + typeof timer);
&#13;
&#13;
&#13;

timer仍然可以在for循环之外使用 - 它会被添加到全局对象中。)