scopes in JavaScript

In modern days more and more applications are made online and as we know JavaScript is pivotal for any web application either simple or rich (RIA). Understanding JavaScript is never more important and JavaScript scope is key to writing bullet-proof code for software professionals who work with web applications mostly.
In this article I am going to talk through what you should know about JavaScript Scoping. We will look into the following topics with an example for each.
  • Scope
  • Global Scope
  • Local Scope
  • Function scope
  • Lexical/static scope
  • Closures
  • ‘this’ object and scope
  • Changing scope with call()
  • Public and private scope

Scope

Scope means the current context of your code. A scope can be global or local. By understanding scope you will understand where variables and functions/objects are accessible , and you will be able to change the scope of your code. It enables us to write more maintainable code as well as to debug much faster.

Global Scope

We are in global scope when we start writing any piece of JavaScript. For example when we declare a variable then the variable is globally defined, which means it is accessible from anywhere in the script.
Example
var app = 'Demo';
console.log(app);
function funcA() {
    console.log("inside a function: ", app);
};
funcA();
Explanation
In the above example, the variable app is defined at global scope. As you can see the variable is called from global scope and also from inside a function. Because the variable is defined a global level it is accessible from anywhere within the script.There is typically only one global scope.
The console output is

Local Scope

When you define a function in the global scope (top level) or within another function (local scope) then the function has its own local scope. The local scope of outer function is accessible to the inner function.
Example 1
  1  var globalVar = "Global Scope";
  2  var funcG = function () {
  3        // Local scope for funcG()
  4         var funcName = 'funcG';
  5         console.log(funcName);
  6         //Local scope can access the global scope
  7         console.log(globalVar);
  8        };
  9    funcG();
 10  
 11    //Global scope cannot access the local scope.
 12    console.log(funcName);
Explanation
The following is the output from the above example 1 where as you can see the variable funcName is undefined in the last line console.log(funcName); because it is defined in local scope inside a function where as the global variable globalVar is accessible in console.log(globalVar); inside local scope.
Example 2
function funcOuter() {
      var outerVar = 'local variable funcOuter();';
      function funcInner(){
          var innerVar = 'local variable funcInner()';
          console.log('inside funcInner : ', innerVar);
          console.log('inside funcInner : ', outerVar);
      }
      console.log(outerVar);
      console.log(innerVar);
  }
Explanation
The following is the output for example 2 where the innerVar is undefined because it is defined insidefuncInner() function and inside local scope which is not accessible to outside function.
At the same time the variable outerVar defined in function funcOuter is accessible inside funcInner()because outer local scope is accessible in inner local scope.

Function Scope

A scope is not created for each statements but for each functions.  When a FOR or WHILE statement is used, a new scope is not created. A function means a new scope that’s the thumb rule.
Example
function funcLoop() {
            for (i = 0; i < 5; i++) {
                console.log('inside loop :', i);
            }
            console.log('outside loop  :', i);
}
funcLoop();
Explanation
The following is the output for the above code and as you can see the variable i defined inside the FORstatement and is accessible from outside the loop too which proves that there is no scope inside the statement.

Lexical/Static Scope

When you define a function within another function, the inner function has access to the scope in outer function. This is called Lexical or Static scope.
Example 1
var parentFunc = function () {

       var param1 = 'parameter 1';
       var childFunc = function () {
           console.log('The parameter is :', param1);
       }
       childFunc();
       console.log(param1);
   }
   parentFunc();
Explanation
The output for the above code is shown below. As you can see, the childFunc() is able to access the varparam1 that is defined in outer function.
The lexical scope works from outer most function to inner most function. It does not work backwards.
Example 2
function outerMost() {
            console.log(innerMost);
            function outer() {
                console.log(innerMost);
                function inner() {
                    console.log(innerMost);
                    function innerMost() {
                        var innerMost = 'inner most';
                    }
                }
            }
        }
outerMost();
Explanation
In the example 2 , the varinnerMost is defined in  innerMost() function and it is not accessible to outer functions. The output is shown below.

Closures

A closure is an object that returns two things: A function and an environment with it.
Closures tie in very closely with Lexical scope. We can return things inside our scope so that they are available in the parent scope.
We can demonstrate it with the following example.
Example
var echo = function (shout) {
          var txt = 'Echoing back : ' + shout;
          return function () {
              console.log(txt);
          }
}
var f1 = echo('Hello');
f1();
Explanation
The functionecho() in the above example, returns a function that displays a text using the vartxt . Thetxt is defined within the echo() function. However , as you can see from the following output , the echo() function is return with the environment (scope) of var txt within it.

'this’ object and scope

The keyword ‘this’ is a very important part of JavaScript programming , and understanding how value of‘this’ is assigned in different places in code and the way how the functions are called is absolutely paramount to write a bug-free code.
The value of ‘this’ at the very top level is the window object. However, the value of ‘this’ is bound to have different values by invoking functions differently. We can easily demonstrate using an example.
Example
var myFunc = function () {
            console.log(this); 
};
myFunc();

var myObj = {};
myObj.method1 = function () {
           console.log(this);
};
myObj.method1();


<p class='scope'>Click</p>
Explanation
The first function myFunc() returns the object window as 'this' which is shown below in the output.
The second function myObj.method1() returns the object myObj for 'this' because the function method1()is part of the object myObj. The output is shown below.
Thirdly, the function display() returns the <p> element for 'this'  because the click() function is called on the element <p>. The output is shown below.
Changing the scope with call()
The scope of 'this' can be changed using the function call() in our code.
Let’s consider the following example
<ul>
   <li>Red</li>
In the ‘for’ loop the developer is trying to log the list items values. But the actual values that are being logged in console are window object because ‘this’ refers to window object in the scope. The console output and the browser output are given below.

Of course we can get the value of list item using array index as below.
console.log(listItems[l]);
In order to demonstrate how a scope can be changed by changing the context, we are going to use thecall ()method in the above code. The same code is rewritten using call () method and we can see how it changes the context of the code and its scope.
var listItems = document.querySelectorAll('ul li');
for (var l = 0; l < listItems.length; l++) {
    (function () {
                 console.log(this);
               }).call(listItems[l]);
}
The output of the above is shown below. This time , as you can see the <li> elements are returns for 'this' object. This way the function call() is very powerful in certain situations.

Public and Private Scope

Inherently , there is no public and private scope in Javascript unlike in other languages but we can emulate them using module pattern.
Lets see the following example
var myModule = (function () {
            var _myPrivateMethod = function () {
                console.log('_myPrivateMethod()');
            }

            return {
                methodOne: function () {
                    console.log('methodOne()');
                }
            };
 })();

 myModule.methodOne();
 myModule._myPrivateMethod();   
  In the above code the line myModule._myPrivateMethod(); would fail because the function_myPrivateMethod() is accessible because it is a private method to myModule.
However the line of code myModule.methodOne(); would succeed though because the method made public with thereturn statement.

Points of Interest

It is worth having a read onbind() and apply() that are similar to call() with slight variation. It is also worth reading more in detail aboutmodule pattern because it is key to Angular JS.

No comments:

Post a Comment

Genuine websites to earn money.

If you are interested in PTC sites then this article is for you. I have personally tried many of the sites and found that the best thing ...