I'm trying to get a deeper understanding of javascript closures , reading about the subject i ran into many similar examples to the following function:
function idCreator(listOfItems) {
var i;
var uniqueID = 100;
for (i = 0; i < listOfItems.length; i++) {
listOfItems[i]["id"] = function (j) {
return function () {
return uniqueID + j;
}()
}
(i);
}
return listOfItems;
}
I understand the main concept of using IIFE inner function and passing the counter variable as a parameter , so for instance in the above example we will be returning the right i (index) , and not the value we get after the end of the loop.
My question is why return an anonymous function, wouldn't returning the value itself work the same?
something like:
function iDCreator(listOfItems) {
var i;
var uniqueID = 100;
for (i = 0; i < listOfItems.length; i++) {
listOfItems[i]["id"] = function (j) {
return uniqueID + j;
}
(i);
}
return listOfItems;
}
The only reason I see to use closures and IIFE's in the example you provide, would be pedagogical: to show how you can swap code with an IIFE, and get the exact same result. Furthermore, it shows how inner functions can still access outer variables.
As said by Quentin, in this very example there is no other logical reason to use closure and IIFE. It is even counter-productive (slows down performance and obfuscates code).
By "definition", an IIFE ("immediately invoked") is not called later on. Its main (and probably only) use is to provide a function scope / closure (as if it were a "block" in other languages that provide block scope), while still avoiding having to use a normal function declaration, where you have to choose an identifier which may collide with another one defined somewhere else.
// Normal function declaration:
function someIdentifier() {}
// Let's immediately call it to execute the code.
someIdentifier();
// what happens if "someIdentifier" was defined somewhere else?
// For example in a previous loop iteration?
That is why the author had to use IIFE's within its for loop.
Within a scope / closure, you can use whatever identifiers (for variables and function declarations) you need, while preventing any collision with identifiers outside the scope. Whether using a function declaration, a function expression, or an IIFE.
// Using an Immediately Invoked Function Expression:
(function idForRecursion() { // being a Function Expression rather than a declaration, you can even use an identifier here to be used for recursion, and it will not pollute the global scope.
var anyIdentifier;
// If "anyIdentifier" were defined outside, this local definition will "shadow" it for the current closure only, without affecting / polluting the outside definition and value.
// As in normal closures, you can still access variables outside the IIFE.
alert(myGlobalVar);
})();
Therefore maybe a more pedagogical example for closure would have been an IIFE where the uniqueID were inside and incremented but hidden from global scope (through a closure) so that no one can fiddle / interfere with it:
var iDCreator = (function () {
var uniqueID = 100; // initial value.
return function innerFn(listOfItems) {
for (var i = 0; i < listOfItems.length; i += 1) {
listOfItems[i]["id"] = uniqueID;
uniqueID += 1;
}
return listOfItems;
};
})(); // "iDCreator" is now a reference to the "innerFn" which has a closure with "uniqueID", but the latter is not accessible from global scope.
// Calling "iDCreator" several times gives truly unique id's, incremented from the previous call.
There's no need to use a function at all.
for (i = 0; i < listOfItems.length; i++) {
listOfItems[i]["id"] = uniqueID + i;
}
Using a closure can be useful when you are assigning a function that will be called later. It isn't here. It looks like the author of the code just got carried away.
Related
Recently, I found myself needing to create an array of functions. The functions use values from an XML document, and I am running through the appropriate nodes with a for loop. However, upon doing this, I found that only the last node of the XML sheet (corresponding to the last run of the for loop) was ever used by all of the functions in the array.
The following is an example that showcases this:
var numArr = [];
var funArr = [];
for(var i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = function(){ return i; };
}
window.alert("Num: " + numArr[5] + "\nFun: " + funArr[5]());
The output is Num: 5 and Fun: 10.
Upon research, I found a a segment of code that works, but I am struggling to understand precisely why it works. I reproduced it here using my example:
var funArr2 = [];
for(var i = 0; i < 10; ++i)
funArr2[funArr2.length] = (function(i){ return function(){ return i;}})(i);
window.alert("Fun 2: " + funArr2[5]());
I know it has to do with scoping, but at first glance it does not seem like it would perform any differently from my naive approach. I am somewhat of a beginner in Javascript, so if I may ask, why is it that using this function-returning-a-function technique bypasses the scoping issue? Also, why is the (i) included on the end?
Thank you very much in advance.
The second method is a little clearer if you use a parameter name that does not mask the loop variable name:
funArr[funArr.length] = (function(val) { return function(){ return val; }})(i);
The problem with your current code is that each function is a closure and they all reference the same variable i. When each function is run, it returns the value of i at the time the function is run (which will be one more than the limit value for the loop).
A clearer way would be to write a separate function that returns the closure that you want:
var numArr = [];
var funArr = [];
for(var i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = getFun(i);
}
function getFun(val) {
return function() { return val; };
}
Note that this is doing basically the same thing as the first line of code in my answer: calling a function that returns a function and passing the value of i as a parameter. It's main advantage is clarity.
EDIT: Now that EcmaScript 6 is supported almost everywhere (sorry, IE users), you can get by with a simpler approach—use the let keyword instead of var for the loop variable:
var numArr = [];
var funArr = [];
for(let i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = function(){ return i; };
}
With that little change, each funArr element is a closure bound do a different i object on each loop iteration. For more info on let, see this Mozilla Hacks post from 2015. (If you're targeting environments that don't support let, stick with what I wrote earlier, or run this last through a transpiler before using.
Let's investigate what the code does a little closer and assign imaginary function names:
(function outer(i) {
return function inner() {
return i;
}
})(i);
Here, outer receives an argument i. JavaScript employs function scoping, meaning that each variable exists only within the function it is defined in. i here is defined in outer, and therefore exists in outer (and any scopes enclosed within).
inner contains a reference to the variable i. (Note that it does not redefine i as a parameter or with the var keyword!) JavaScript's scoping rules state that such a reference should be tied to the first enclosing scope, which here is the scope of outer. Therefore, i within inner refers to the same i that was within outer.
Finally, after defining the function outer, we immediately call it, passing it the value i (which is a separate variable, defined in the outermost scope). The value i is enclosed within outer, and its value cannot now be changed by any code within the outermost scope. Thus, when the outermost i is incremented in the for loop, the i within outer keeps the same value.
Remembering that we've actually created a number of anonymous functions, each with its own scope and argument values, it is hopefully clear how it is that each of these anonymous functions retains its own value for i.
Finally, for completeness, let's examine what happened with the original code:
for(var i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = function(){ return i; };
}
Here, we can see the anonymous function contains a reference to the outermost i. As that value changes, it will be reflected within the anonymous function, which does not retain its own copy of the value in any form. Thus, since i == 10 in the outermost scope at the time that we go and call all of these functions we've created, each function will return the value 10.
I recommend picking up a book like JavaScript: The Definitive Guide to gain a deeper understanding of JavaScript in general so you can avoid common pitfalls like this.
This answer also provides a decent explanation on closures specifically:
How do JavaScript closures work?
When you invoke
function() { return i; }
the function is actually doing a variable look-up on the parent call-object (scope), which is where i is defined. In this case, i is defined as 10, and so every single one of those functions will return 10. The reason this works
(function(i){ return function(){ return i;}})(i);
is that by invoking an anonymous function immediately, a new call-object is created in which the current i is defined. So when you invoke the nested function, that function refers to the call-object of the anonymous function (which defines whatever value you passed to it when it was invoked), not the scope in which i was originally defined (which is still 10).
So lets say I have some code:
//Javascript
var elements = [];
function addNumbah1(){
var i = 1;
elements.push(i);
}
function addNumbah2(){
var i = 2;
elements.push(i);
}
And that goes on up to addNumbah999(), is it bad form to declare the i variable every time? Will that break anything? Should I do:
//Javascript
var elements = [];
var i
function addNumbah1(){
i = 1;
elements.push(i);
}
function addNumbah2(){
i = 2;
elements.push(i);
}
Short answer: NO, JS hoists all variable declarations to the top of the scope, regardless of how many times you've declared them:
var i = 0
for (var i=0;i<10;i++)
{
var j = i%2;//declared 10 times, on each iteration
}
Will be translated to
var i, j; //i is undefined at this point in the code.
for (i = 0;i<10;i++)
{
j = i%2;//declared 10 times, on each iteration
}
In your first example, you're declaring i as a variable in a function's scope, which is what you must do to avoid cluttering the global scope. The memory these variables use is allocated when the function is called, and deallocated when the function returns (roughly, closures form an exception, but that would take us to far). Consider this:
var i = 10;
function someF()
{
var i = 1;
alert(i);
}
someF();//alerts 1 <-- value of i, local to someF
alert(i);//10, global i is unchanged
But if you were to omit the var:
function someF()
{
i = 1;
alert(i);
}
You'll see that 1 is alerted twice. If JS can't find a variable declaration in the current scope, it will look in the higher scopes until a var is found. If no variable is found, JS will create one for you in the highest scope (global). Check my answer here on how implied globals work for a more detailed example, or read the MDN pages, especially the section on Name conflicts
Lastly, I'd like to add that globals, especially implied globals, are evil. Also know that the ECMA6 standard is clearly moving away from global variables and introduces support for true block-scopes. As you can see here
Oh, and if you want to check if a function uses implied globals: 'use strict'; is a great thing:
(function()
{
'use strict';
var localVar = 123;//ok
impliedGlobal = 123;//TypeError!
}());
As you can see, implied globals are not allowed. See MDN on strict mode for the full explanation
The second form, with global i might actually be a bit slower because it's defined in a higher scope, and variables defined in a higher scope take longer to resolve.
Aside from any performance considerations just stick with common guidelines unless performance is really an issue. In this case: scope your variables as narrowly as possible.
I would strongly advise you to use the first form.
The first way you did it is fine. Each instance of i would have no knowledge of the other i in the other functions.
You should read this tutorial on global versus local variables
Also, could I suggest an optimization. Why can't you just do the following to cover any number (instead of separate functions for each number)?
var elements = [];
function addNumbah(number){
elements.push(number);
}
It is okay to declare variables with same name in different functions.
Variables declared inside a function only exist in the scope of that function, so having the same variable name across different functions will not break anything.
In fact, it is good form to keep variables in as small of a scope as possible! Global variables can be difficult to manage and can create really bad bugs, especially if one function isn't done using the variable when another function tries to access it.
Specifically for simple variables, declaring
var i = 0;
every time is perfectly fine.
You can declare a variable multiple times..In your code you are declaring Variable i in different scopes here:
//Here you are declaring variable i local to addNumbah1,2 functions
var elements = [];
function addNumbah1(){
var i = 1;
elements.push(i);
}
function addNumbah2(){
var i = 2;
elements.push(i);
}
//Here v /variable i has been declared globally
var elements = [];
var i
function addNumbah1(){
i = 1;
elements.push(i);
}
function addNumbah2(){
i = 2;
elements.push(i);
}
Note that although you can declare a variable multiple times but generally its not a good programming practice as it may cause bugs/problems in your application
just a bit confused by this code
var counter = function() {
//...
var count = 0;
return function () {
return count = count + 1;
}
}
var nextValue = counter();
console.log(nextValue());
nextValue.count = 7;
console.log(nextValue());
console.log(nextValue.count);
console.log(nextValue());
Output is
1
2
7
3
It's counter intuitive. There are two representations of count. One on the outerfunction nextValue and one that only the inner anonymous function can see.
Correct, or are my missing something?
The expression nextValue.count does not refer to the local variable "count" declared inside the function. It is not possible, in fact, to create a reference to a variable local to a function from code outside the function. What you're referencing there is simply a property of the function object.
So, yes, the "count" variable that the returned function has access to is effectively completely private to that function, and it is persisted in the closure formed by the call to the "counter" function.
If you did want that to work, you could do this:
function counter() {
function actual() {
return actual.count = actual.count + 1;
}
actual.count = 0;
return actual;
}
edit — (fixed bogus code) the name "actual" inside gives the returned function safe access to the function object itself; originally I typed "this" there, and that would not work unless the external code set it up explicitly.
The way you describe it, count is effectively a private variable. When you're assign to nextValue.count, you're creating a separate property--not accessing the internal count being incremented by your counter.
I'm reading "Javascript: The Good Parts" and am totally baffled by what's really going on here. A more detailed and/or simplified explanation would be greatly appreciated.
// BAD EXAMPLE
// Make a function that assigns event handler functions to an array of nodes the wrong way.
// When you click on a node, an alert box is supposed to display the ordinal of the node.
// But it always displays the number of nodes instead.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (e) {
alert(i);
}
}
};
// END BAD EXAMPLE
The add_the_handlers function was intended to give each handler a unique number (i). It fails because the handler functions are bound to the variable i, not the value of the variable i at the time the function was made:
// BETTER EXAMPLE
// Make a function that assigns event handler functions to an array of nodes the right way.
// When you click on a node, an alert box will display the ordinal of the node.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (e) {
alert(i);
};
}(i);
}
};
Now, instead of assigning a function to onclick, we define a function and immediately invoke it, passing in i. That function will return an event handler function that is bound to the value of i that was passed in, not to the i defined in add_the_handlers. That returned function is assigned to onclick.
I think this is a very common source of confusion for newcomers to JavaScript. First I would suggest checking out the following Mozilla Dev article for brief introduction on the topic of closures and lexical scoping:
Mozilla Dev Center: Working with Closures
Let's start with the bad one:
var add_the_handlers = function (nodes) {
// Variable i is declared in the local scope of the add_the_handlers()
// function.
var i;
// Nothing special here. A normal for loop.
for (i = 0; i < nodes.length; i += 1) {
// Now we are going to assign an anonymous function to the onclick property.
nodes[i].onclick = function (e) {
// The problem here is that this anonymous function has become a closure. It
// will be sharing the same local variable environment as the add_the_handlers()
// function. Therefore when the callback is called, the i variable will contain
// the last value it had when add_the_handlers() last returned.
alert(i);
}
}
// The for loop ends, and i === nodes.length. The add_the_handlers() maintains
// the value of i even after it returns. This is why when the callback
// function is invoked, it will always alert the value of nodes.length.
};
We can tackle this problem with more closures, as Crockford suggested in the "good example". A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. In JavaScript, the environment of the closure consists of any local variables that were in-scope at the time that the closure was created:
// Now we are creating an anonymous closure that creates its own local
// environment. I renamed the parameter variable x to make it more clear.
nodes[i].onclick = function (x) {
// Variable x will be initialized when this function is called.
// Return the event callback function.
return function (e) {
// We use the local variable from the closure environment, and not the
// one held in the scope of the outer function add_the_handlers().
alert(x);
};
}(i); // We invoke the function immediately to initialize its internal
// environment that will be captured in the closure, and to receive
// the callback function which we need to assign to the onclick.
Rather than having the callbacks all sharing a single environment, the closure function creates a new environment for each one. We could also have used a function factory to create a closure, as in the following example:
function makeOnClickCallback (x) {
return function (e) {
alert(x);
};
}
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = makeOnClickCallback(i);
}
It's all about closures. In the first example, "i" will be equal to "nodes.length" for every click event handler, because it uses "i" from the loop which creates the event handlers. By the time the event handler is called, the loop will have ended, so "i" will be equal to "nodes.length".
In the second example, "i" is a parameter (so a local variable). The event handlers will use the value of the local variable "i" (the parameter).
In both examples any node that's passed has an onclick event handler bound to it (just like <img src="..." onclick="myhandler()"/>, which is bad practice after all).
The difference is that in the bad example every closure (the event handler functions, that is) is referencing the exact same i variable due to their common parent scope.
The good example makes use of an anonymous function that gets executed right away. This anonymous function references the exact same i variable as in the bad example BUT since it is executed and provided with i as its first parameter, i's value is assigned to a local variable called ... eh? ... i, exactely - thus overwriting the one defined in the parent's scope.
Let's rewrite the good example to make it all clear:
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (newvar) {
return function (e) {
alert(nevar);
};
}(i);
}
};
Here we replaced i in the returned event handler function with newvar and it still works, because newvar is just what you'd expect - a new variable inherited from the anonymous function's scope.
Good luck figuring it out.
It has to do with closure.
When you do the thing in the bad example,
when you click each node, you will get the latest i value (i.e. you have 3 nodes, no matter what node you click you will get 2). since your alert(i) is bound to a reference of variable i and not the value of i at the moment it was bound in the event handler.
Doing it the better example way, you bound it to what i as at the moment that it was iterated on, so clicking on node 1 will give you 0, node 2 will give you 1 and node 3 will give you 2.
basically, you are evaluating what i is immediately when it is called at the line }(i) and it got passed to parameter e which now hold the value of what i is at that moment in time.
Btw... I think there is a typo there in the better example part... it should be alert(e) instead of alert(i).
I am learning YUI and have occasionally seen this idiom:
<script>
(function x(){ do abcxyz})();
</script>
Why do they create a function just to invoke it?
Why not just write:
<script>
do abcxyz
</script>
For example see here.
They're taking advantage of closures.
A short explanation: Since JS uses function-level scoping, you can do a bunch of actions within a function and have it remain in that scope. This is useful for invoking code that doesn't mess with the global namespace. It also allows one to make private variables - if you declare a variable inside of an anonymous function and execute it immediately, only other code inside of the anonymous function can access that variable.
For example, suppose I want to make a global unique id generator. One might do code like this:
var counter = 0;
var genId = function()
{
counter = counter + 1;
return counter;
}
However, now anyone can mess with counter, and I've now polluted the global namespace with two variables (counter and genId).
Instead, I could use a anonymous function to generate my counter function:
var genId = function()
{
var counter = 0;
var genIdImpl = function()
{
counter = counter + 1;
return counter;
}
return genIdImpl;
}();
Now, I only have one variable in the global namespace, which is advantageous. More importantly, the counter variable is now safe from being modified - it only exists in the anonymous function's scope, and so only the function genIdImpl (which was defined in the same scope) can access it.
It looks like in YUI's example code, they just want to execute code that doesn't pollute the global namespace at all.
They want to avoid namespace collisions, I'd guess. Seems as a good practice in JS.