Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

All You Need to Know about Scoping in JavaScript

4.50/5 (4 votes)
4 Jan 2016CPOL6 min read 11.3K   44  
Examples and explanations about scope in JavaScript

Introduction

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

JavaScript
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:

Image 1

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

JavaScript
  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.

Image 2

Example 2

JavaScript
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 inside funcInner() 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.

Image 3

Function Scope

A scope is not created for each statement, but for each function. 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

JavaScript
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 is defined inside the FOR statement and is accessible from outside the loop too which proves that there is no scope inside the statement.

Image 4

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

JavaScript
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 var param1 that is defined in outer function.

The lexical scope works from outer most function to inner most function. It does not work backwards.

Image 5

Example 2

JavaScript
function outerMost() {
            console.log(innerMost);
            function outer() {
                console.log(innerMost);
                function inner() {
                    console.log(innerMost);
                    function innerMost() {
                        var innerMost = 'inner most';
                    }
                }
            }
        }
outerMost();

Explanation

In example 2, the var<code> innerMost is defined in innerMost() function and it is not accessible to outer functions. The output is shown below:

Image 6

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

JavaScript
var echo = function (shout) {
          var txt = 'Echoing back : ' + shout;
          return function () {
              console.log(txt);
          }
}
var f1 = echo('Hello');
f1();

Explanation

The function echo() in the above example returns a function that displays a text using the var txt. The txt is defined within the echo() function. However, as you can see from the following output , the echo() function is returned with the environment (scope) of var txt within it.

Image 7

'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

JavaScript
var myFunc = function () {
            console.log(this); 
};
myFunc();

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


<p class='scope'>Click</p>
<script type="text/javascript">
       var p = document.querySelector('.scope');
        var display = function () {
            console.log(this);
        };

p.addEventListener('click', display, false);

Explanation

The first function myFunc() returns the object window as 'this' which is shown below in the output.

Image 8

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:

Image 9

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:

Image 10

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:

HTML
<ul>
   <li>Red</li>
   <li>Green</li>
   <li>Yellow</li>
   <li>Blue</li>
</ul>


<script type="text/javascript">
    var listItems = document.querySelectorAll('ul li');
    for (var l = 0; l < listItems.length; l++) {
        console.log(this);
    }
</script>

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:

Image 11

Of course, we can get the value of list item using array index as below:

JavaScript
console.log(listItems[l]);

In order to demonstrate how a scope can be changed by changing the context, we are going to use the call () 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.

JavaScript
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.

Image 12

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.

Let's see the following example:

JavaScript
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();<font color="#111111" face="Segoe UI"> </font>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 is made public with the return statement.

Points of Interest

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)