Monday, March 25, 2013

Angry Birds of JavaScript: Red Bird - IIFE

Introduction


A diabolical herd of pigs stole all of the front-end architecture from an innocent flock of birds and now they want it back! A team of special agent hero birds will attack those despicable pigs until they recover what is rightfully theirs, front-end JavaScript architecture!

In this post we will take a look at the Red Bird who attacks with the force of their trusty IIFE, the basic block of all privacy.

What Was Stolen by the Pigs?


For ages the birds used to litter the global namespace (the window object) with their custom objects and functions. Over time the birds slowly learned techniques to protect their objects from the global namespace, however, since the recent pig invasion all of their anti-global secrets have been stolen! Thankfully the birds are fortunate that a one foul exists with the knowledge of this secret and plans to attack the pigs to unleash what is rightfully theirs.

How Objects Become Global?


There are several ways that an object can become global. Part of the battle is just knowing the various ways.

1. Declaring an Object in the Window Scope

In the following example there two variables declared, type and attack. These variables were declared in the top level scope and therefore are accessible off of the window object.


2. Not Declaring an Object in Any Scope

One of the most dangerous and easiest things to do in JavaScript is to accidentally declare a global variable when you didn't mean to. If you forget to declare a variable then JavaScript declares it for you as a global! This is usually not what you meant to do and could expose parts of your application that you didn't intend.


3. Specifically Adding an Object to the Window

You also have the opportunity to expose variables to the global namespace intentionally. You can easily do this by accessing the window object and adding a property or method manually. It isn't a good idea to use this technique deep inside your code, but it is worth nothing that you can.


Why Are Global Objects a Problem?


  • Conflicts within Your Code

    There is a risk that developers within your own company may define the same function, method, or property that already exists in your application. If you have no mechanism to reduce the number of items in the global namespace your risk of accidentally reassigning a variable grows as your application gets larger and more complex.

    You may dismiss this reason because you have rigid code reviews and all your developers know your codebase inside out. If that describes you, then check out the next reason ;)

  • Conflicts with Your Code and Third-Party Libraries

    Another danger of having multiple global objects is that your code could conflict with third-party libraries that you are using. There are a lot of libraries, plugins, and frameworks out there and not all of them are as aware and conscious about keeping their global variables to a minimum. Your code and the libraries you include could clash and override each-other's behavior which can cause unexpected results.

    You may dismiss this reason because you deeply scrutinize all third-party libraries that your team uses and are fully aware of what global variables are exposed by these libraries. If that describes you, then check out the next reason :)

  • Conflicts with Your Code and Browser Add-ons/Extensions/Plugins

    The final danger of having multiple global objects is that your code could conflict with the browser itself. What!?! Lets take Google Chrome for an example. Chrome's add-ons are JavaScript based and all of your installed add-ons run on your web page when it is loaded. You never know what add-ons your users have installed and as a result there is a risk that those add-ons will expose global variables that conflict with your code-base.

    Does this seem far-fetched? Well, it can at first, but I've actually seen a high profile website (not going to mention which one) run into this very problem. I was trying to use the website and it was broken. I knew the developer so I reached out to him. After some back and forth it turned out I had an add-on installed that broke the website. I contacted the add-on author and they updated their code and now all is fine.

Various Ways to Protect Yourself


Although the above code snippets were very small and simple, they all exposed way too many variables to the global namespace. So, how do we protect ourselves?

  • Object Literal

    The easiest way to help prevent global variable proliferation is to protect yourself with an object literal that limits gathers all objects that would have been global and attaches them to once central object.


  • Immediately Invoked Function Expression

    The Immediately Invoked Function Expression (IIFE) is another technique to get around the global issue. This technique is more complicated than the Object Literal, but provides much more power as well. This technique allows the developer to expose public and private properties and methods to the consumer.

    Before we get into what this looks like, lets work through some of their weird syntax that we are about to see. The scoping of variables in JavaScript is determined via the function scope and not block scope. So, if you have a variable declared inside an if statement for example it would be available everywhere inside its containing function. This might seem a little jarring to some developers that are used to C, C++, C#, Java, or similar languages.

    So, we are going to use this functional scope idea to create an anonymous function (function with no name) and immediately invoke it.


    Unfortunately, the above snippet doesn't work in JavaScript because it can't parse it correctly. The idea is solid, but the implementation is off just a little bit. Thankfully, there is an easy way to let JavaScript know that we know what we are doing and that is to surround the expression with an extra set of parenthesis.


    The following pattern is known as the Revealing Module Pattern. You should notice the use of the IIFE to create the special functional scope and the note-worthy part is the end where you return the parts of the scope that you want to be public to object and anything not returned will be private.


    You may also run across this alternate syntax that is popular in many libraries and frameworks. The pattern uses the IIFE, but this one passes in the global variable to use as a namespace. The window.bird = window.bird || {} code snippet is a fancy way to check if the bird object already exists and if it doesn't then to create a new one. Whatever gets added to the object from within the IIFE becomes public and whatever memory isn't attached to the object stays private. The nice thing about this pattern is that it can be repeated and build up a library with various components.


Attack!


The following is a simple Angry Birds clone using boxbox, a framework for the box2dweb JavaScript physics library, written by Bocoup's Greg Smith.

Press the space bar to launch the Red Bird and you can also use the arrow keys.


Conclusion


These techniques are vital for a front-end application so that it can protect itself from other code and it also gives the opportunity to structure your code in a way that is encapsulated from its surroundings.

There are many other frotn-end architecture techniques that have been stolen by the pigs. Tune in next time as the next Angry Bird takes its revenge! Dun, dun, daaaaaaa!

No comments:

Post a Comment