Search code examples
closuresjavascript-objects

What is a difference in lifecycle between 'entity' object and function object in javascript?


Why does this code snippet outputs 5 (as expected due to scope chain) ?

let arr = []
var firstFunc;
for(var i = 0; i < 5; i++) {
    var iterFunc = function () {
        return function() {
            return i
        }
    }
    arr.push(iterFunc())
}

console.log(arr[0]())

but this outputs {a: 0}:

let arr = []
var firstFunc;
for(var i = 0; i < 5; i++) {
    var iterFunc = function () {
        return {
            a: i
        }
    }
    arr.push(iterFunc())
}

console.log(arr[0])

what memory allocation logic occurs under the hood ? Why 'entity' object persists current value in contrast to closure ?


Solution

  • Returning i or {a: i} here doesn't matter.

    The important thing is that in first example, iterFunc() returns a function and is inside that (not yet invoked) function where i or {a: i} is evaluated.

    Having i is always holding a scalar (immutable) value, that value is what you get in place. (If i would have been an object, a reference to that object would be returned and if, its contents mutated, you could see that mutations).

    Being immutable value, you will get that value. But, as you know, i value changes in time, so the key thing here is WHEN that value is read.

    If you see at your first example, in console.log(...) statement, you are intentionally invoking it as the function you know it is (the unnamed function returned by iterFunc()) and, that time, i is holding a value of 5.

    If, in your first example, you just change following line:

    arr.push(iterFunc())
    

    by

    arr.push(iterFunc()())
    

    ...and, of course:

    console.log(arr[0]())
    

    by

    console.log(arr[0]) // Same of your second example.
    

    You will realize that output will be the same in both cases (0).