Adsense-HeaderAd-Script


Advertisement #Header

22 Dec 2015

JavaScript for Java Programmers :Closure and Variable Scope


1st let us take a look at Javascript Variable Scope and Hoisting.

For Java developers this would be a strange world by looking at how Variable Scope works in JavaScript.

Eg: Java program to demo variable scope for local and global variables.
?

  
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public class studentShow{
     
    private static class Student
    {
        private  static String name="Anwar";
         
        private static void studentName(){
            System.out.println("Inside 1. name= "+name);
            String name = "Ravi";
            System.out.println("Inside 2. name= "+name);
        }
    }  
     
    public static void main(String args[])
    {
        System.out.println("Outside 1. name= "+Student.name);
        Student.studentName();
        System.out.println("Outside 2. name= "+Student.name);
    }
}

  
public class studentShow{
    
    private static class Student
    {
        private  static String name="Anwar";
        
        private static void studentName(){
            System.out.println("Inside 1. name= "+name);
            String name = "Ravi";
            System.out.println("Inside 2. name= "+name);
        }
    }   
    
    public static void main(String args[]) 
    {
        System.out.println("Outside 1. name= "+Student.name);
        Student.studentName();
        System.out.println("Outside 2. name= "+Student.name);
    }
}
Output
?

  
1
2
3
4
Outside 1. name= Anwar
Inside 1. name= Anwar
Inside 2. name= Ravi
Outside 2. name= Anwar

  
Outside 1. name= Anwar
Inside 1. name= Anwar
Inside 2. name= Ravi
Outside 2. name= Anwar

Now see how a similar program outputs in Javascript

  
01
02
03
04
05
06
07
08
09
10
11
12
13
14
var name = "Anwar"  // global variable
     
function studentName()
{
    console.log ("Inside 1. name= "+ name); // undefined;  Due to Variable Hoisting
    var name = "Ravi"; // local variable; only accessible in this studentName function​
    console.log ("Inside 2. name= "+ name); // Ravi
}
console.log ("Outside 1. name= "+name); // Anwar: the global variable
     
studentName();     
console.log ("Outside 2. name= "+name); // Anwar: the global variable

  
var name = "Anwar"  // global variable
    
function studentName()
{
    console.log ("Inside 1. name= "+ name); // undefined;  Due to Variable Hoisting
    var name = "Ravi"; // local variable; only accessible in this studentName function​
    console.log ("Inside 2. name= "+ name); // Ravi
}

console.log ("Outside 1. name= "+name); // Anwar: the global variable
    
studentName();      

console.log ("Outside 2. name= "+name); // Anwar: the global variable
Output
?

  
1
2
3
4
Outside 1. name= Anwar
Inside 1. name= undefined
Inside 2. name= Ravi
Outside 2. name= Anwar

  
Outside 1. name= Anwar
Inside 1. name= undefined
Inside 2. name= Ravi
Outside 2. name= Anwar
Variable Hoisting

Why we got undefined instead of Anwar?
In Javascript, all variable declarations are hoisted (lifted and declared) to the top of the function, if defined in a function, or the top of the global context, if outside a function.

Note: Only variable declarations are hoisted to the top, not variable initialization or assignments

So the above JavaScript program is seen by the JavaScript Engine as
?

  
1
2
3
4
5
6
7
8
function studentName()
{
    var name; // only declaration is hoisted to top of the function
    console.log ("Inside 1. name= "+ name); // Since initialization is not hoisted ;
                                            // current value is undefined
    name = "Ravi";
    console.log ("Inside 2. name= "+ name);
}

  
function studentName()
{
    var name; // only declaration is hoisted to top of the function
    console.log ("Inside 1. name= "+ name); // Since initialization is not hoisted ; 
                                            // current value is undefined
    name = "Ravi";
    console.log ("Inside 2. name= "+ name); 
}

 Local Variables
In JavaScript, another weird thing about variable scope is its based  on Function- level instead of Block-level Scope (variables scoped to surrounding curly brackets);

A JavaScript program to demo the Function level Variable scope
?

  
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
var age = 15;
     
function studentName() {
    var name = "Ravi"
    console.log ("1. Outside Block level name= "+ name); //Ravi
     
    if(age<18) {
        var name = "Master. "; //local variable;
        //for Java developers, name variable scope should be limited to if block
        console.log("Inside if Block - name= "+name); // Master
    }
    else {
        var name = "Mr. "//local variable;
        //for Java developers, name variable scope should be limited to else block
        console.log("Inside else Block - name= "+name);
    }
    console.log ("2. Outside Block level name= "+ name);  // outside if-else block
        //for Java developers, Output should be Ravi   
        // But since in JS, the there is no block-level variable scope just Function level scope
        // Master is  the value of name
}

  
var age = 15;
    
function studentName() {
    var name = "Ravi";  
    console.log ("1. Outside Block level name= "+ name); //Ravi
    
    if(age<18) {
        var name = "Master. "; //local variable;
        //for Java developers, name variable scope should be limited to if block
        console.log("Inside if Block - name= "+name); // Master
    }
    else {
        var name = "Mr. ";  //local variable;
        //for Java developers, name variable scope should be limited to else block
        console.log("Inside else Block - name= "+name);
    }
    console.log ("2. Outside Block level name= "+ name);  // outside if-else block
        //for Java developers, Output should be Ravi    
        // But since in JS, the there is no block-level variable scope just Function level scope
        // Master is  the value of name
}
Output
?

  
1
2
3
1. Outside Block level name= Ravi
Inside if Block - name= Master.
2. Outside Block level name= Master.

  
1. Outside Block level name= Ravi
Inside if Block - name= Master.
2. Outside Block level name= Master.

Global Scope if not Declared 

Any variable in a function that is not declared will become a global variable.

?

  
01
02
03
04
05
06
07
08
09
10
11
12
var name = "Anwar"  // global variable
console.log ("1. Outside name= "+ name);   
function studentName() {
    name = "Ravi"// global variable
    // If you don't declare your local variables with the var keyword,
    // they are part of the global scope
    console.log ("  Inside name= "+ name); //Ravi
}
     
studentName(); 
console.log ("2. Outside name= "+ name);

  
var name = "Anwar"  // global variable
console.log ("1. Outside name= "+ name);    

function studentName() {
    name = "Ravi";  // global variable
    // If you don't declare your local variables with the var keyword, 
    // they are part of the global scope
    console.log ("  Inside name= "+ name); //Ravi 
}
    
studentName();  
console.log ("2. Outside name= "+ name);
Output
?

  
1
2
3
1. Outside name= Anwar
  Inside name= Ravi
2. Outside name= Ravi

  
1. Outside name= Anwar
  Inside name= Ravi
2. Outside name= Ravi

All non-declared variables in JavaScript will pollute the global scope so its best pratice to declare as local variables inside Functions.


What is a closure?
A closure is an inner function that has access to the outer (enclosing) function’s variables & parameters.

The closure has three scope chains:
  1. it has access to its own scope (variables & parameters defined in its Function), 
  2. it has access to the outer function’s variables & parameters, and 
  3. it has access to the global variables.

Note : Inner function cannot call the outer function’s arguments object

eg: JS Demo of Closure
?

  
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
function studentTopRanks(firstRank, secondRank)
{
  var msg ="The Rank list : ";
   
  function print()
  {
    // print() is closure inner function
     
    // It has access to local variables of enclosed outer function
    // It also has access to parameters - firstRank, SecondRank
    // of enclosed outer function
     
    return msg + "1st rank - " + firstRank
             + ", 2nd rank - " + secondRank;
  }
   
  return print(); 
}
     
studentTopRanks('Ravi','Anwar');

  
function studentTopRanks(firstRank, secondRank) 
{
  var msg ="The Rank list : ";
  
  function print()
  {
    // print() is closure inner function
    
    // It has access to local variables of enclosed outer function
    // It also has access to parameters - firstRank, SecondRank 
    // of enclosed outer function
    
    return msg + "1st rank - " + firstRank
             + ", 2nd rank - " + secondRank;
  }
  
  return print();  
}
    
studentTopRanks('Ravi','Anwar');


Weirdness of Closures in JavaScript

1. Closures have access to the outer function’s variable even after the outer function returns
?

  
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function studentTopRanks(firstRank)
{
  var msg ="The Rank list : ";
   
  function print(secondRank)
  {
    // print() is closure inner function
     
    // It has access to local variables of enclosed outer function
    // It also has access to parameters - firstRank, SecondRank
    // of enclosed outer function
     
    return msg + "1st rank - " + firstRank
             + ", 2nd rank - " + secondRank;
  }
   
  return print; 
  // return print;   we return the print function object, instead of
  // return print(); which returns the String of the msg
   
}
     
var printObjVar = studentTopRanks('Ravi');
// At this juncture, the studentTopRanks outer function has returned.
// It returns a function Object and assigned to variable printObjVar
var display = printObjVar("Jackson");
// The closure (print) is called here after the outer function has returned above
// Yet, the closure still has access to the outer function's variables and parameter
console.log(display);

  
function studentTopRanks(firstRank) 
{
  var msg ="The Rank list : ";
  
  function print(secondRank)
  {
    // print() is closure inner function
    
    // It has access to local variables of enclosed outer function
    // It also has access to parameters - firstRank, SecondRank 
    // of enclosed outer function
    
    return msg + "1st rank - " + firstRank
             + ", 2nd rank - " + secondRank;
  }
  
  return print;  
  // return print;   we return the print function object, instead of
  // return print(); which returns the String of the msg
  
}
    
var printObjVar = studentTopRanks('Ravi'); 
// At this juncture, the studentTopRanks outer function has returned.
// It returns a function Object and assigned to variable printObjVar

var display = printObjVar("Jackson");
// The closure (print) is called here after the outer function has returned above
// Yet, the closure still has access to the outer function's variables and parameter
console.log(display);


2. Closures store references to the outer function’s variables; not the actual value.

Douglas Crockford demonstrated the use of Private Members in JavaScript using this technique.

?

  
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Student()
{
    var name = "Master";
    return {
         
    // We are returning an object with some inner functions
    // All the inner functions have access to the outer function's variables
     
        getName: function() 
        {
            // This inner function will return current value of
            // outer functions name variable
            // Even after the setName function changes it
          return name;
        },
        setName: function(newName) 
        {
            // This inner function will change the outer function's variable anytime
            name = newName;
        }
    }
}
var studObjVar = Student(); // At this juncture, the Student outer function Object has returned.
studObjVar.getName(); // Master
studObjVar.setName("Ravi"); // Changes the outer function's variable
studObjVar.getName(); // Ravi: It returns the updated celebrityId variable

  
function Student() 
{
    var name = "Master";
    return {
        
    // We are returning an object with some inner functions
    // All the inner functions have access to the outer function's variables
    
        getName: function()  
        {
            // This inner function will return current value of 
            // outer functions name variable
            // Even after the setName function changes it
          return name;
        },
        setName: function(newName)  
        {
            // This inner function will change the outer function's variable anytime
            name = newName;
        }
    }
}

var studObjVar = Student(); // At this juncture, the Student outer function Object has returned.
studObjVar.getName(); // Master
studObjVar.setName("Ravi"); // Changes the outer function's variable
studObjVar.getName(); // Ravi: It returns the updated celebrityId variable


No comments:

Post a Comment