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();
});
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.
source to share
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());
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.
source to share
I expect to
someFn
create a closure that spans the variablesidx
andval
, 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 :-)
source to share