JavaScript Secrets

Inside a closure

As briefly described in the previous post, a closure is the scope that is created when a function is able to access variables that are defined outside the function. Normally a function only has access to variables defined within it’s own body. The following code sample illustrates this:

var externalVar = "port";
var sail;

function harbour (){
   var internalVar = "dock";

   function quay () {
      if(externalVar){
      alert("I can see the port");
      }
      if(internalVar){
      alert("I can see the dock");
      }

   }
   sail = quay;

  }
   harbour();

   sail();

run the code

Animation with Closures

In the example below, one anonymous function is used to access three variables (tick, elem and timer) in order to animate the div element. The function maintains reference to these variables throughout the setInterval loop. As a result the variables should not be in global scope where other objects could interfere and cause a conflict.

<!doctype html>
   <head>
      <title>Animation with Closures</title>
	  <style>
	   #ship{
	      width: 120px;
		  height: 120px;
		  background-color: red;
		  position: relative;
	   }
	  </style>
   </head>
   <body>
   <div id="ship">Sailing</div>
   <script type="text/javascript">
      function animateShip(elemId){
         var elem = document.getElementById(elemId);
         var tick = 0;

         var timer = setInterval(function(){
           if(tick < 120) {
              elem.style.left = elem.style.top = tick + "px";
			  console.log(tick);
              tick++;
            }
           else {
               clearInterval(timer);
               if(tick == 120) {
               alert("Tick was accessed via a closure");
               }
               if(elem && timer) {
               alert("Element elem and timer also accessed via a closure");
              }

           }
         }, 10);
     }
   animateShip("ship");
   </script>

   </body>
</html>

run the code
It should be noted that the previous example would still work even the variables were defined in global scope, outside the animateShip() function. This is shown in the next example:

<!doctype html>
   <head>
      <title>Animation with Closures</title>
	  <style>
	  #ship {
            width: 150px;
            height: 70px;
            background-color: #fdd;
            color: #fff;
            text-align: center;
            font-size: 18px;
            position: relative;
        }
	  </style>
   </head>
   <body>
   <div id="ship">Sailing</div>
   <script type="text/javascript">
      var tick = 0;
      var elem;
      var timer;
      function animateShip(elemId){
         elem = document.getElementById(elemId);

         timer = setInterval(function(){
           if(tick < 120) {
              elem.style.left = elem.style.top = tick + "px";
			  console.log(tick);
              tick++;
            }
           else {
               clearInterval(timer);
               if(tick == 120) {
               alert("Tick was accessed via a closure");
               }
               if(elem && timer) {
               alert("Element elem and timer also accessed via a closure");
              }

           }
         }, 10);
     }
   animateShip("ship");
   </script>

   </body>
</html>

run the code
However when you try to animate two or more elements with this setup, as shown below, a serious problem arises. Only the last element gets animated, because it over writes all previous instances of the variables.

<!doctype html>
   <head>
      <title>Animation with Closures</title>
      <style>
         #ship {
         width: 150px;
         height: 70px;
         background-color: #fdd;
         color: #fff;
         text-align: center;
         font-size: 18px;
         position: relative;
        }
        #ship2 {
        width: 150px;
        height: 70px;
        background-color: orange;
        color: #fff;
        text-align: center;
        font-size: 18px;
        position: relative;
        left: 150px;
        }
   </style>
   </head>
   <body>
   <div id="ship">Sailing ship1</div>
   <div id="ship2">Sailing ship2</div>
   <script type="text/javascript">
      var tick = 0;
      var elem;
      var timer;
      function animateShip(elemId){
         elem = document.getElementById(elemId);

         timer = setInterval(function(){
           if(tick < 120) {
              elem.style.left = elem.style.top = tick + "px";
			  console.log(tick);
              tick++;
            }
           else {
               clearInterval(timer);

           }
         }, 10);
     }
   animateShip("ship");
   animateShip("ship2");
   </script>

   </body>
</html>

run the code
When we restore the variables to the initial scope within the animateShip() function, then both divs are animated simultaneously. This insightful example shows the real power of closures.It’s sort of an Aha! moment in the JavaScript closure ecosystem. Imagine creating multiple animations in a complex application, for example an accordion with several items; All the items can be animated by a single jQuery object. You can now understand why the concept of closures is so important in object oriented JavaScript. Libraries like jQuery, Backbone, Knockout and Ember could not exist without closures.

<!doctype html>
   <head>
      <title>Animation with Closures</title>
      <style>
	   #ship {
         width: 150px;
         height: 70px;
         background-color: #fdd;
         color: #fff;
         text-align: center;
         font-size: 18px;
         position: relative;
        }
        #ship2 {
        width: 150px;
        height: 70px;
        background-color: orange;
        color: #fff;
        text-align: center;
        font-size: 18px;
        position: relative;
        left: 150px;
        }
   </style>
   </head>
   <body>
   <div id="ship">Sailing</div>
   <script type="text/javascript">

      function animateShip(elemId){
         var tick = 0;
         var elem = document.getElementById(elemId);

         var timer = setInterval(function(){
           if(tick < 120) {
              elem.style.left = elem.style.top = tick + "px";
			  console.log(tick);
              tick++;
            }
           else {
               clearInterval(timer);

           }
         }, 10);
     }
   animateShip("ship");
   animateShip("ship2");
   </script>

   </body>
</html>

run the code

Binding a function’s context

In the code sample below, shows how a functions context can be forced to have a certain value. The bind() function has a closure within which an anonymous function is being used to change the context of another method. The code is rather convoluted and needs to be untangled. This technique is being used to resolve the problem caused the browsers default behaviour of assigning the context of a click event to the button element that was clicked. Here, the context has been switched to the myButton object.

<html>
   <head><title>Binding context</title></head>
   <body>
   <button id="btn">Click here</button>
<script type="text/javascript">
   function bind(context, name){
     return function(){
       return context[name].apply(context, arguments);
     };
   }

var myButton = {
    clicked: false,
    click:  function (){
      this.clicked = true;
      if(myButton.clicked){
      alert("You clicked myButton!" + "in this context " + this);
      }

      }
    };

var el = document.getElementById("btn");
el.addEventListener("click", bind(myButton, "click"), false);
</script>
</html>

run the code

Binding function context in JavaScript