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