Javascript: The window object and IIFE

Browsers come with two very useful objects: document and window. The document object is necessary for interacting with the rendered HTML (called the Document Object Model or DOM). However, the window object is equally important.

I see many up and coming Javascript programmers abuse the window object unknowingly. I’d like to shed some light on how to avoid thrashing window. This will naturally introduce “immediately invoked function expressions” (IIFE) that are used to hide data.

The window object contains a ton of useful goodies (attributes) for our use. Basically, almost all of the “built-in” Javascript functions and datatypes are within the window object.

If that wasn’t enough, the window object is also the storage medium for user-defined components. What I mean by this is that if you’d like to create a collection of functions that you can incorporate in multiple scripts, you need to make that collection (or every individual function) available to the window object. Once that’s done, you can simply say window.myCoolFunction() to harness the power of your custom function.

So how do you hook a function into the window object? Well, this is done unknowingly many times.

Most beginners start writing javascript by creating a text file with a .js extension, linking to that javascript file in their html file using the script tag and then hammering away with some DOM manipulation.

Declaring Variables

So you’ll start with some code like:

name = "Joel Kemp";
console.log("My name is", name);

The problem with this is that when you declared and defined that variable name, it was immediately registered on the window object. Go ahead and check it in your console, window.name should exist. Start writing a lot more code and before long, you have many variables polluting window. The reason why name was stored in window is that when you omit the var keyword in declaring variables, it’s immediately stored in the global window object.

Why “polluting”? Think about this: in modern javascript apps, we incorporate the power of many different libraries in our scripts. Most notably, you’ve referenced jQuery in your html file, right alongside your custom scripts. What if the jQuery library was built with tons of variables latching onto the window object? More specifically, what if jQuery defined a variable called name that it desperately needed for its internal workings? Well, your custom 2-liner above just destroyed jQuery’s meaning of the variable name. This is what we call a ‘global namespace collision.’

It’s obviously not great for jQuery to have been coded in a way that pollutes the window object and in fact, the library is not coded that way. The jQuery library adds two global variables that are attached to the window object: jQuery and its alias $. That’s it! All of the other internal variables declared don’t exist outside of that library – no where to be found within the window object.

The var keyword

As I said, variables declared without the var keyword attach themselves to window. So you might be thinking, “well hell, let’s var everything!” Variables declared with the var keyword exist within the scope in which they’re defined. So we’ll rewrite our 2-liner to be:

var name = "Joel Kemp";
console.log("My name is", name);

Problem is that window.name still exists! How could that be? (No, not because you forgot to refresh the page). The question should be “which scope are we in?” The answer is that we’re in the global scope.

Function Scope

Javascript has function scope. This means that variables/functions declared within a function exist only within that function. This sounds like what we want: our name variable needs to exist only within a function, not within window.

So let’s do just that:

function hiding() {
  // This only exists within the hiding() function
  var name = "Joel Kemp";
  console.log("My name is", name);
}

// Need to call the function so it executes
hiding();

console.log(name); // Output is undefined

Success! We successfully hid the variable name. However, we unknowingly attached the function name hiding to the window object… Crap. So how do we avoid attaching the function name to window?

We could use the var keyword to define this function:

var hiding = function () {
  // This only exists within the hiding() function
  var name = "Joel Kemp";
  console.log("My name is", name);
};

hiding();
console.log(name); // Output is undefined

But we run into the same problem where the identifier hiding is still within the global scope, so var doesn’t help us.

Immediately Invoked Function Expressions (IIFE)

It would be great if we could define a function and not give it a name. Javascript has a construct that’s perfect for this: anonymous/unnamed functions.

That would make hiding look like:

// No name
function () {
  // This only exists within the hiding() function
  var name = "Joel Kemp";
  console.log("My name is", name);
}

But then how would we actually call that function to execute if it doesn’t have a name? There’s another construct to the rescue: immediately invoked function expressions.

If you wrap the anonymous function within parentheses, then you can immediately invoke it with another set of parentheses like so:

(function () {
  // This only exists within the hiding() function
  var name = "Joel Kemp";
  console.log("My name is", name);
})(); // The last pair indicates a function call

This is the best of all worlds: we have an unnamed function that executes immediately. The inner variable name is declared with the var keyword within a function’s scope, so it doesn’t leak to the window object.

These ideas should be incorporated into every javascript that you write. You should always wrap your code in an IIFE as to not pollute the global namespace. You should always use the var keyword and declare variables within a function scope. If you ever need something (function or data) to be accessible to other scripts, then (sparingly) attach that function/data to the window object explicitly like so:

(function () {
  // Everyone should know my name
  window.name = "Joel Kemp";
  console.log("My name is", name);
})(); // The last pair indicates a function call

console.log(name); // Output is "Joel Kemp"

Hope it helps! Let me know if you have any specific questions below.