JavaScript Closure行为不正确

时间:2017-07-12 14:11:36

标签: javascript closures

这是一小段代码,我觉得闭包函数有一种奇怪的行为......



var arr = [5, 6, 7, 8, 9, 0];
var someFn;

arr.forEach(function(val, idx) {
  if (!someFn) {
    someFn = function() {
      console.log(`B: ${idx} : ${val}`);
    };
  }
  console.log(`A: ${idx} : ${val}`);
  someFn();
});




最终的控制台输出是......

A: 0 : 5
B: 0 : 5
A: 1 : 6
B: 0 : 5
A: 2 : 7
B: 0 : 5
A: 3 : 8
B: 0 : 5
A: 4 : 9
B: 0 : 5
A: 5 : 0
B: 0 : 5

我希望someFn在forEach处理时处理增量值,但它总是输出第一个值"idx: 0, val: 5"

我不认为这是正确的行为,因为someFn正在创建一个封闭变量idxval的闭包,并且这两个变量在外部函数中都在变化。

感谢有人能够解释这种行为。

2 个答案:

答案 0 :(得分:0)

根据这个问题other answer

  

闭包是一个堆栈帧,在函数开始执行时分配...

因此每个函数调用都会创建自己的闭包。

forEach做的是它需要一个函数(回调)并多次调用它(从数组中传递元素及其索引和数组)。因此,forEach的每次迭代都会创建一个新的闭包。

您在第一次迭代时定义someFn(之后永远不会重新声明),因此它被捕获的闭包是第一次迭代的闭包。因此,唯一可用的值是第一次迭代的值。

闭包与函数本身无关,与调用有关

示例:



function theFunction(value) {
  return function() {
    return value;
  };
}

var someFn1 = theFunction("Ibrahim");
var someFn2 = theFunction("John");

console.log("someFn1: ", someFn1());
console.log("someFn2: ", someFn2());




在示例中,每次调用theFunction都会创建一个新的闭包。 someFn1someFn2,虽然它们是由相同的功能生成的,但无法访问相同的关闭。

代码中等效于theFunction的是传递给forEach的同义函数,它被执行(因此创建clousures)的次数与数组中的元素一样多。

答案 1 :(得分:0)

  

我希望someFn创建一个封闭变量idxval的闭包,这两个变量在外部函数中都在变化。

不,他们不会改变。它们是每次调用外部函数时实例化的新变量。第一次迭代中的两个变量,在那里创建的闭包确实关闭,保持它们的值。

要获得预期的行为,可以使用没有函数的循环,只需要声明两个变量:

var arr = [5, 6, 7, 8, 9, 0];

for (var [idx, val] of arr.entries()) {
//   ^^^^^^^^^^^^^^ global variables
  if (!someFn) {
    var someFn = function() {
      console.log(`B: ${idx} : ${val}`);
    };
  }
  console.log(`A: ${idx} : ${val}`);
  someFn();
}

虽然usually that's exactly what we try to prevent: - )