Alex
Alex

Reputation: 892

Why write an IIFE that returns a closure over the IIFE’s parameters instead of writing a direct closure?

Learning JavaScript and can't figure out why these two functions are different. I saw this example (I added names to the functions):

var txt = ["a", "b", "c"];

for (var i = 0; i < 3; ++i ) {
  setTimeout((function (msg) {
    return function () { console.log(msg); }
  })(txt[i]), 100);
}

I see that a function that calls console.log is being returned. So I thought, why not just return it directly:

var txt = ["a", "b", "c"];

for (var i = 0; i < 3; ++i ) {    
  setTimeout(function() { console.log(txt[i]); }, 100);
}

This ends up showing 'undefined.' I understand that it's because it's trying to access txt[3] because after one second the loop has finished and i has been set to 3, but I don't understand how the original setup avoided this problem.

Upvotes: 0

Views: 105

Answers (4)

cocco
cocco

Reputation: 16706

Example 1

The closures execute the script instantly and also allow you to pass a parameter inside which is stored and remains stored inside that function. parameter==param

(function(param){})(parameter)

In your example the function returns another function which will be executed by setTimeout.

(function(param){
 return function(){
  alert(param)
 }
})(parameter)

And as you passed the parameter previously to the function it will return the right value.

Example 2

The setTimeout is called 3 times very fast but the parameter is not stored anywhere so it takes the last value know from txt & i and as the loop is ended before the setTimeout is executed the value is 3


basically in the first example you store every txt[i] inside each function you create with those closures.

In the second one you don't store the txt[i]'s anywhere. you just tell the setTimout function to alert txt[i], which after 1second is the last one created by the for loop.

Upvotes: 1

Juan Guerrero
Juan Guerrero

Reputation: 613

This is a concurrency problem.

setTimeout creates a "thread" for each execution, but won't evaluate the function until the timeout expires.

so, after a second, when the first timeout expires, your for loop has ended (with i having 3 as value), so accessing the txt[i] returns undefined. Try printing the value of i inside the function with console.log

Upvotes: 0

Ed Heal
Ed Heal

Reputation: 60007

You need to read up about closures. See this answer How do JavaScript closures work? to understand them.

Upvotes: 1

C. K. Young
C. K. Young

Reputation: 223073

In the first version, txt[i] has been bound to a new variable, msg, which is a different location for each function being created.

In the second version, i is the same location for each of the functions because i's scope is further up; there isn't a new i variable being created each time through the loop.

Upvotes: 0

Related Questions