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 executeshiding();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 namefunction () { // 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 callconsole.log(name); // Output is "Joel Kemp"
Hope it helps! Let me know if you have any specific questions below.