JavaScript Closing Wrong Behavior

Here is a small piece of code in which I feel that the closure function has strange behavior ...

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();
});
      

Run codeHide result


Final console output ...

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

      

I expect to someFn

handle the incremental value when the forEach is processed, but always outputs the first value that is "idx: 0, val: 5"

.

I don't think this is the correct behavior, because it someFn

creates a closure that spans the variables idx

and val

, and both of those variables are modified in the outer function.

Appreciate if someone can kindly explain this behavior.

+3


source to share


2 answers


As per this other answer on SO:

a closure is a stack stack that is allocated when the function runs ...

Thus, each function call creates its own closure.

What it does forEach

is that it executes the function (callback) and calls it multiple times (passing the element from the array along with its index and array). Thus, each iteration forEach

creates a new closure.

You define someFn

on the first iteration (never get around after that), so the closure it hit is the closure of the first iteration. Thus, the only available values ​​are those in the first iteration.

A closure is not related to the function itself, it is related to its calls .



Example:

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

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

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

Run codeHide result


In this example, each call theFunction

creates a new closure. someFn1

and someFn2

although they are generated by the same function, they do not have access to the same closure.

In your code, the equivalent theFunction

is an anounymous function passed to forEach

that gets executed (and thus creates clousures) as many times as there are elements in the array.

0


source


I expect to someFn

create a closure that spans the variables idx

and val

, and both of those variables are modified in the outer function.

No, they don't change. These are new variables that are created each time the external function is called. Two variables from the first iteration, over which the closure was created, closed, retain their values.

To get the expected behavior, you can use a non-function loop where you only declare two variables:



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();
}

      

Although usually what we're trying to prevent is :-)

0


source







All Articles