Saturday 24 August 2019

javascript closure Immediately Invoked Function Expression



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;
}


Answer



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.

No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...