After Immediately Invoked Function Expression, it's time for another very important topic.
At the start, let's write the often used, function hello once again, but instead of returning console.log, let's return the next function!
We see here something that thanks to the previous parts should be quite clear to notice.
Let's do this step by step.
We have a function hello with one paramter, say
Hello returns the next function, this time with the parameter name.
When the function hello is invoked in the seventh line, Syntax Parser, checking character by character knows that if we ended on hello ("Hello") we would just get the function code.
Then, we invoke the returned function and give it the "Tom" as an argument.
Thanks to that, we'll get "Hello Tom" in the console.
Now, let's change the code a bit.
As you can see, we've split the function invocation into two parts. To the variable hi, we save the invoked hello function with the argument "Hi". Next, as this is a function, we can invoke it with the argument "Joe".
Everything works as it should.
Now, however, let's think about one important stuff.
From previous posts you could find out that each of the Execution Contexts contains its own space in memory for variables, functions.
And what happens to everything that is stored in memory when the Execution Context is removed from the stack?
Here, a very important thing happens. After executing the code in Execution Context, there is still a trace in memory to all variables we created there.
Finally, I would like to show one example, which is very often found in tutorials that want to explain what the closures are.
What do you think we will get after invoking each function ?
Did anyone expect this? Or maybe you bet more on the result 1, 2 and 3? If you thought, however, it would be 1, 2 ,3, I will try to break the function into small steps to better understand what Closure is.
- In the above example, we have the function myFunction in which at the beginning we created an empty array and saved it in the arr variable (third line).
- Then, using for loop, starting at 0, incrementing by 1, until the i variable is less than 3, we will execute the code.
- This part of the code is nothing more than adding elements to the created array.
- When i = 0, condition 0 < 3 is true, so we add the first element to our array using the push method. In our case, this is a function.
- We increment by 1, now i = 1, and the rest of the code is executed until i < 3.
- When the condition is no longer fulfilled, we will go out of for loor and as you can see in the fifteenth line, our main function will return arr array.
- Then we save to the returned variable, the returned value from the myFunction function.
- As these are functions in our array, we can invoke them using the parenthesis, as we do in lines 20, 21 and 22.
Now let's see how Execuion Contexts look.
- At the beginning, a Global Execution Context is created which is hoisting myFunction.
- After invoking the myFunction function, another Execution Context is created.
- Inside it there are two things arr and i.
Now the main issue begins, which causes us to get three times 3.
- We know that the variable is initially 0. The entire code in the loop is executed until the variable is 3 (not 2 !).
- In memory, the i value is saved, which is now 3.
Although Execution Context of myFunction has already been removed from Execution Stack, as the entire code has already been executed. In the memory, i = 3 has been saved, and the functions that has been pushed into the array have access to it.
So, as we now know that i variable always equals 3. The three returned values will be 3.
And what if I wanted it to work as "intended". What if we wanted 1,2,3 to be returend ?
ES6 let fixes that but I will talk about it soon.
It will be about functional programming and it will be the last one before we get into ES6 features.