Using IIFEs in JavaScript to control variable scope
Because creating too many global variables is iffy
On a recent project, a few of us have been challenged to take our JavaScript skills to a new level. We’ve even learned a few new tricks from a group of outside developers that we’re working with who specialize in JavaScript.
One such trick is using immediately-invoked function expressions (IIFEs), which are often used to take advantage of JavaScript’s scope rules to funnel in certain global variables and avoid creating too many of your own globals.
The basic concept of an IIFE (lovingly pronounced “iffy,” occasionally referred to as a self-executing or self-invoked anonymous function) is to wrap a portion of JavaScript in an anonymous function that gets called immediately:
(function () { // your code here })();
Wrapping the function in parentheses turns it into an expression rather than a declaration. The empty set of parentheses that follows tells the interpreter to run that expression as a function. It is a more compact and anonymous equivalent to the following:
var foo = (function () { // your code here }); foo();
Take control of your globals
Writing code like this might seem redundant until you give it more substance, of course. Let’s use an example I recently came across in a website I was working on at home.
This website, unfortunately, has dependencies on both the jQuery and Prototype libraries. Both libraries use $
as a global variable; Prototype as a shortened way to access document.getElementById()
, and jQuery for, well, pretty much everything it does. Because of this, the value of $
changes depending on which library is included last. In this case, Prototype was the last-included library, so $
belongs to Prototype.
Now if I want to use jQuery’s functions, instead of using $( ... )
, I have to use jQuery( ... )
. This is a little annoying, what with jQuery being the more widely-used library that more developers are familiar with. To fix this, I wrapped my code in an IIFE and passed it the jQuery
global variable:
(function ($) { $(document).ready(function () { // my code }); })(jQuery);
This means that, no matter what the global variable $
means outside my IIFE, within it I’m explicitly telling it to run jQuery functions. I could just as easily assign jQuery
to any other unused variable and it would have the same effect:
(function (p) { p(document).ready(function () { // my code }); })(jQuery);
Keep your variables to yourself
Aside from funneling in global variables to whatever values I want, I can also use IIFEs to prevent variables from being added to the global scope.
For example, you might run the following code on a web page outside of any function:
var x = "hello"; alert(x); // alert dialog with the text "hello"
By doing this, x
is now a global variable. If x
was assigned elsewhere before this script was called, it’s now reassigned to the value "hello"
. Not always ideal. To avoid this without having to name and call a new function, wrap your code in an IIFE. This keeps your variables within a smaller scope and still runs the lines immediately:
(function() { var x = "hello"; alert(x); // alert dialog with the text "hello" })();
Now, x
is only assigned to the value "hello"
for the duration of the IIFE. If x
was assigned globally before the IIFE, it would keep that value after the IIFE runs:
var x = "foo"; (function() { var x = "hello"; alert(x); // alert dialog with the text "hello" })(); alert(x); // alert dialog with the text "foo"
As you’ve seen, the IIFE convention can be a great standard practice when writing your own libraries and plugins, when extending JavaScript where you may not be aware of every context in which certain variable names are used and to prevent too much data from creeping its way into the global scope.
12 comments
Trey Piepmeier commented:
Thanks, Josh!
Even though I was in the training with you, it really helps to have it summarized like this.
Aaron commented:
Great info, thank you! This will be especially useful when pasting in other people’s jQuery code (and they all use $) rather than using jquery or .noConflict( ) and find/replace like I’ve been doing. No good burritos in Nashville though?
Josh Mock commented:
Aaron, I’ve since found a decent burrito or two in Nashville. But nothing will beat what you can get in California!
Glad I could help give some clarity on your jQuery scoping issues.
Jeremy G commented:
Great usage tutorial!
I will point out however, for script kiddies like myself who like to copy and paste, that you forgot the terminating curly bracket for your IIFE in the examples where you enclosed the $/jQuery global variable (which are the 3rd and 4th code entries).
Line 5 should end })(jQuery); instead of )(jQuery);
Or are there browsers that parse the JS just fine that way?
Josh Mock commented:
Nice catch, Jeremy! I don’t think JS parsers would like that, actually. I’ve updated the code samples accordingly.
azopco commented:
What about setting global vars from within the IIFE?
azopco commented:
Hello,
Why my last comment isn’t getting posted? My question still remain: how to access/set global vars from within the IIFE???
Thank you…
Josh Mock commented:
Sorry azopco! We got your comment but it got stuck in spam moderation.
To set global variables from inside an IIFE, assign values to window.yourVariableName. This only works in JavaScript you run in your browser, as the global “window” variable is not available in Node.js.
azopco commented:
Thank you Josh for your reply!
There is another thing I discovered about IIFES is that we can pass more than one variable:
var somethingElse = ‘dada’;
(function ($, smthingElse) {
console.log(smthingElse);
})(jQuery, somethingElse);
// output “dada” in the console
azopco commented:
By the way, the window.varName works for variables, but it doesn’t work for functions :(
window.myFunction(); doesn’t work from within an IIFE, while it works outside.
it’s difficult to keep a track of all used functions (that are available in the global scope) and pass them to the IIFE.
Any other technique?
azopco commented:
Sorry for the many posts, but update:
Actually window.myFunction() does work but you need to declare your function this way:
myFunction = function() { … }
Which is simply saving the function in a variable. Declaring it like this will NOT work:
function myFunction() { … }
Jonathan commented:
Thanks much for this great tutorial. It’s very helpful. One thing I don’t get though is how the use of the IFFE is really helping in terms of avoiding the global variable. In the example given, the variable isn’t global at all. The variable “x” is simply defined within the scope of the function. Therefore, it behaves exactly as it would in old-style javascript, e.g., it’s the same as writing it this way:
function myFunction() {
var x = ‘whatever’;
alert(x);
}
myFunction();
So while you avoid adding a function name, since you’re using an anonymous function, you’re not really doing anything in terms of avoiding a global variable “x” that couldn’t be done in basic JavaScript. The whole point of having global variables, of course, is so that they can keep their value when called from multiple, independent functions. So I’m still not sure how the IFFE notation helps one to accomplish that.