Used to demonstrate JavaScript closures and IIFEs.
A Pen by Matt Stills on CodePen.
Used to demonstrate JavaScript closures and IIFEs.
A Pen by Matt Stills on CodePen.
| // by default, variables are assigned to the "window" object (the global namespace) | |
| init = function () { | |
| console.log('Initializing page') | |
| } | |
| if (window.init === init) { | |
| console.log("Yes... they are the same!"); | |
| } | |
| // but "init" is a really common function name... we don't want another script to use it | |
| // and accidentally overwrite ours or vice-versa. Closures to the rescue! | |
| (function () { | |
| var init = function () { | |
| console.log("Closure init();") | |
| } | |
| init(); | |
| }()); // <-- this is an IIFE | |
| // IIFE look strange at first but let's deconstruct it and you'll see that it actually isn't so scary! | |
| var myFunc = function () { | |
| // ^--starting here | |
| var init = function () { | |
| console.log("Non IIFE Closure init();") | |
| } | |
| init(); | |
| }; // <-- and ending here, but remove the semicolon | |
| // remember how I mentioned functions are first-class citizens? Below | |
| // is a standard function call to "myFunc" which we defined above. | |
| // I wrapped it with some unnecessary extra parens which JavaScript | |
| // will ignore in this situation. | |
| (myFunc()); | |
| // Now copy from the start to end points defined above in the "myFunc" definition | |
| /* | |
| function () { | |
| // ^--starting here | |
| var init = function () { | |
| console.log("Non IIFE Closure init();") | |
| } | |
| init(); | |
| } | |
| */ | |
| // And paste it in to replace the "myFunc" keyword: | |
| (function () { | |
| // ^--starting here | |
| var init = function () { | |
| console.log("IIFE Closure init() #2;") | |
| } | |
| init(); | |
| }()); | |
| // Voila! Notice that it now looks exactly the same as above. | |
| // But it gets better. This function accepts parameters just like | |
| // any other. However, you are given the opportunity to give the | |
| // reference an alias for use inside your closure. This is handy | |
| // for a variety of situations however it is not necessary. You | |
| // may simply want to use the same variable name for the closure's | |
| // reference to the parameter for the sake of simplicity. | |
| // Quick demo of that: | |
| var valuableData = 'really?'; | |
| (function (valuableData) { // <-- and name the closure's internal reference here | |
| console.log(valuableData); | |
| valuableData = "not really imo"; | |
| }(valuableData)); // <-- you pass through the "external" reference here | |
| console.log('External "valuableData":', valuableData) | |
| // Be aware that complex types like objects and arrays are passed by value. | |
| // This means changes made to that variable inside of the closure will change | |
| // the external reference as well. This is however not the case with simple | |
| // types like strings as evidenced above. This will be demonstrated in the next | |
| // example. | |
| // Suppose you have a data object with a really long name... | |
| window.myExtremelyLongAndUnweidlyObjectWithImportantData = { | |
| importantProp: "yes", | |
| anotherImportantProp: "also yes", | |
| aFunc: function () { | |
| console.log('myExtremelyLongAndUnweidlyObjectWithImportantData.aFunc() just got called...') | |
| } | |
| }; | |
| // And you use it a lot within your code. Inside your closure, you can simple alias it to something | |
| // much more shorter. Again though, because objects are passed through the closure by reference, the | |
| // changes you make to the alias will apply to the external object which is being aliased. Let's see | |
| // this in action... | |
| (function (important) { | |
| important.aFunc(); // its functions and properties are available | |
| // However, if you already a property, it changes everywhere that this object is referenced (such) | |
| // as in the global scope. | |
| console.log('importantProp inside closure before altering', important.importantProp); | |
| // Sometimes this is desirable, sometimes not | |
| important.importantProp = 'no'; | |
| }(window.myExtremelyLongAndUnweidlyObjectWithImportantData)); | |
| console.log('importantProp back outside of the closure', window.myExtremelyLongAndUnweidlyObjectWithImportantData.importantProp); |