Closure can simply be defined as "In JavaScript, the inner function has the access to all the variables defined outside of that functions."
Here is a simple code with Closures:
function sayHelloToClosures(yourName) { var text = 'Hello Closures from' + yourName; var sayAlert = function() { alert(text); } sayAlert(); }
Here in this example inner function sayAlert() has access to text defined in outer function sayHelloToClosures(), yes that simple concept is Closure.
Closures says the local variables for a function is not de-allocated after the function has returned.
Lets see it another way:
function outerFunction(x) { var z = 3; return function (y) { alert(x + y + z); } } var innerFunction = outerFunction(2); // innerFunction is now a closures. innerFunction(10);
Here when we call outerFunction() it sets the values x = 2 and z = 3 and returns a function which takes a parameter y and sum of x, y and z. This retuning function get assigned to innerFunction() on return. In general the variables x and z should be destroyed as outerFunction() has completed its execution and it returned successfully, but closures say it exists for innerFunction() and whenever we call innerFunction() values of x and z will always be the same defined by the outerFunction().
so whenever we call innerFunction() it will add x + z = 5 to y and alert the value.
So when a function is invoked in JavaScript , it creates a new execution context. This context has access to Parent objects with the arguments for the current function get invoked, this execution context also has access to the variables declared outside of its scope.
The simplest example:
var foo = 20; function myFunction(x) { var bar = 6; console.log(foo); // will output 20 console.log(bar); // will output 6 console.log(x); // will output 10 } myFunction(10);
As we know JavaScript always uses the Object by reference when it passes as argument, so if we pass objects to a function as closures and call innerFunction() which updates the value of the object, on the next execution of innerFunction() it will have updated value, not the value set by the outerFunction().
Let see the example:
function outerFunction(x) { var z = 3; return function (y) { x=x+1;//x++ alert(x + y + z); } } var myVal = new Number(2); var innerFunction = outerFunction(myVal); // innerFunction is now a closures. innerFunction(10); //will alert 16 innerFunction(10); //will alert 17 innerFunction(10); //will alert 18
On first execution it will get the Number Object and increment it and set to closures function, but here it also updated the value of the object as the object in JavaScript passed by reference, so updating its value will update the original object, so next time on calling innerFunction() it will get incremented value and so on. So on each time function will get incremented value.
Loops and Closures
How closures can cause issues in loops and how to solve it?
As closure tells you that innerFunction() use the outer or upper scope variables copy(if it is not object), so it may cause some ambiguous functionality in loops, like:
var myFunctions = {}; for (var i = 0; i < 3; i++) { // let's create 3 functions myFunctions[i] = function() { // and store them in myFunctions console.log("My value: " + i); // each should log its value. }; } for (var j = 0; j < 3; j++) { myFunctions[j](); // and now let's run each one to see }It will output:
My value: 3 My value: 3 My value: 3instead of:
My value: 0 My value: 1 My value: 2
why?
because, your myFunctions() is bound to outer-scope variable i which is changed in each loop so after complete loops it value is 3, that is the reason it is printing 3 each time.
So, How to solve it?
Pass variable i as a parameter, instead of using it directly, as we know if we pass a parameter function makes its own local copy of the variable (if it is not object type which pass by reference). So each time function has its own local copy of variable which not get updated by loop iteration. Here is a solution for above issue:
var myFunctions= []; function createMyFunction(i) { return function() { console.log("My value: " + i); }; } for (var i = 0; i < 3; i++) { myFunctions[i] = createMyFunction(i); } for (var j = 0; j < 3; j++) { myFunctions[j](); // and now let's run each one to see }Now as each time creatMyFunction() will have its own copy so it output the correct result, as expected:
My value: 0 My value: 1 My value: 2
In your code:
ReplyDeleteconsole.log(bar); // will output 35
I alert'ed this and the output is 6, not 35. How do you log 35?
Yes, it will be 6!!! updated post accordingly. thanks :)
DeleteThank you so much! I was having trouble understanding this concept until I found this page.
ReplyDeleteOutput of loops and closures is 0,1,2 but posted as 1,2,3
ReplyDeletethanks for the feedback
DeleteThank you, very useful. Is it a function can be written as array[i] = function(num){function {return num}}(i),to get the same result as myFunction()?
ReplyDeleteThanks. very useful. Output Loops and Closures is posted as below
ReplyDeleteMy value: 2
My value: 2
My value: 2
As it should be
My value: 3
My value: 3
My value: 3
Dear Zaher,
ReplyDeleteYou have typed above, the output is:
My value: 2
My value: 2
My value: 2
where it should read:
My value: 3
My value: 3
My value: 3
regards,
Eyad
This was really helpful, thank you!!
ReplyDeletethis made so many things clearer.. thanks
ReplyDelete