Everything you need to know about Javascript variable scope

Most of the people assume that scope of variable in Javascript is very much similar to other programming languages like Java and C. But there are a number of points where the behavior is different and very complex. Not only beginners, even few experienced Javascript programmers find it difficult to understand socpe of variable in Javascript. These points are to be understood well to master Javascript and code with less syntactical as well as logical errors

The scope of a variable is the portion of the program code for which the variable's name has meaning and for which the variable is said to be "visible". Javascript has two types of scopes global and local(function) level scope. Variables declared globally that are visible throughout the javascript program come under global scope. Variables declared inside functions, may have same name as global varibles, are accessible only within that function are local variables.

Before we start I would like to mention a set of important points where Javascript behaves differently. I will discuss on all these points later in this article.

1) No block level scope(except a special case - Block-scoped variables) 
2) Variables are hoisted (variables declaration are moved to top and then run)
3) Chaining of scopes. Any function defined within another function has a local scope which is linked to the outer function.

Global Variables
Any variable declared globally or in simple terms any variables declared outside functions are termed as global variables. Also any property assigned to window object is also treated as global variable. It is because in browsers, all global variables are properties of the window object. In Javascript it is not mandatory to declare variables with var keyword. If variables are defined without var(no var) outside functions, they are treated as global variable. "no var" variable definition inside function will look up the scope chain until it finds the variable or hits the global scope (at which point it will create it).
But there is a significant difference between variable declaration with var and "no var" declaration apart from its automatic global scope access.Here is a link that has a very good explanation to this difference.

Let us take an example.

// Simple variable declared globally
var simpleGlobal = "Simple varibale declared globally";

// Variable not declared so belongs to its global scope
notDeclaredGlobal = "Not declared globally so treated as global scope";

function foo() {
 // Variable not declared so belongs to its global scope
 notDeclaredInsideFunction = "Not declared inside function so treated as global scope";
    // Variable is defined in global scope when assigned as window property
     window.anyWindowGlobalProperty = "Global variable defined as window property";
  
    alert("Inside function");
    alert(simpleGlobal);
    alert(notDeclaredGlobal);
    alert(notDeclaredInsideFunction);
}
foo();
alert("Outside function");
// Below alert is only valid if foo(where notDeclaredInsideFunction get declared automatically) is called.
alert(notDeclaredInsideFunction);
alert(anyWindowGlobalProperty)

JsFiddle link for above example

In above example simpleGlobal is declared as global variable. notDeclaredGlobal is a "no var" variable so it is also treated to be in global scope. notDeclaredInsideFunction is another "no var" variable inside function so browser will look up for the declaration in the scope chain but when not found it will also be treated to be in the global scope. But this gets only declared when this function is called. So if we use notDeclaredInsideFunction without calling the function foo then it will give error stating that notDeclaredInsideFunction is not defined. anyWindowGlobalProperty is a property assigned to window object so it will also be a global property.

Javascript do not have block level scope. Here is an example.

var i;
for(var i=0;i<5;i++)    {
    var j = 5;
}
    
alert("i="+i); // prints 5
alert("j="+j); // prints 5


JsFiddle link for above example

Both variables i and j are visible outside the for loop. It is because block level scope is not considered in Javascript. So both these variable are visible in the current scope i.e global scope. Also variable i declared twice so both being the global scope later one overrides the former one.

Local variables
JavaScript has function-level scope. Variables declared within a function are local variables and are only accessible within that function or by functions inside that function. Javascript uses scope chains to establish the scope for a given function. Each function defined has its own nested scope. Any function defined within another function has a local scope which is linked to the outer function. It's always the position in the source that defines the scope. When resolving a variable, javascript starts at the innermost scope and searches outwards.

var name = "Saurab";

function showName () {
 var name = "Parakh"; // local variable that is only accessible in this this function
 console.log (name); // Parakh
}
console.log (name); // prints Saurab as resembles the global variable

Here in above example there are two variables name. Variable name within function showName is local to this function so the value of this is only visible within this function. Outside function boundaries global variable name is accessed.
Also you can notice that the local variable has higher priority than variable from outer scope. Lets see another example to be more clear.


var name = "Saurab";

function foo() {
  var name = "Kumar";
   var newFun = function() {
      var name = "Parakh";
        alert(name); //alerts Parakh i.e local and innermost
   };
    newFun();
    alert(name); //alerts Kumar i.e innermost in current scope
}
foo();
alert(name); //alerts Saurab which is only visible

JsFiddle link for above code

In above example we noticed that in case of mutiple varibles with same name, the one which is innermost and local in the current scope is given the highest priority. Here in function newFun, "Parakh" gets printed as it is the value of the innermost name variable.

Also as discussed earlier, if the variable is not declared within the function than it belongs to the global scope.

Variable Hoisting
Function and variable declarations are moved to the top of their current scope i.e hoisted automatically by the Javascript interpreter
Lets take an example.

function foo() {
 alert("Hi")
 var name = "Saurab";
}

is actually interpreted like this:

function foo() {
 var name;
 alert("Hi");
 name = "Saurab";
}

So the variable name declaration is actually hoisted(moved to the top). The assignment portion remains at it its original place as shown in above example.
Lets see how function declaration are hoisted.

foo(); // valid call because hoisted
function foo() {
 alert("Inside function  foo")
}

is hoisted to

function foo() {
 alert("Inside function  foo")
}
foo();

In case of function declarations, the entire function body is hoisted. Here the foo is called before the foo is declared. But it works good as it is hoisted by Javascript interpreter.

There can be some confusing cases too where variable with same is hoisted. Lets take another example.
var num = 100;
foo();

function foo(){

    // This prints "undefined", because aNumber is also defined locally below.
    document.write(num);

    if (false)
    {
        var num = 123;  
    }
}

When JavaScript executes a function, it first looks for all variable declarations, for example, var num;. It creates the variables with an initial value of undefined. If a variable is declared with a value, for example, var num = 123;, then it still initially has the value undefined and takes on the declared value only when the line that contains the declaration is executed. In above example num prints undefined. That is because we have a local variable num with the same name and that gets hoisted.
So resultant code will look something like this.

var num = 100;
foo();

function foo(){
 var num;
    // This prints "undefined", because aNumber is also defined locally below.
    document.write(num);

    if (false)
    {
        num = 123;  
    }
}

Block-scoped variables
ECMAScript 6  introduces support for block-scoped variables in the form of let and const.
 For these variables, the braces {. . .} define a new scope. When you set one of these variables to a particular value, the value applies only to the scope in which it is set.

The following example illustrates the use of let and block-scoping.

 var a = 4;
for (var i = 0; i < 7; i++) {
  let j = i+1;
  console.log(j);
}
console.log(j); // will throw ReferenceError: j is not defined

In above example let statement defines a new scope with braces. So variable j outside the for loop throws ReferenceError: j is not defined
Also block-scoped variables defined with let statement are not hoisted. Let us take another example to understand this.

function example(x) {
    console.log(y); // ReferenceError: y is not defined
    if (x) {
        let y = 5;
    }
}

In the above example use of variable throws error stating variable y is not defined as variable y is defined later in the code using let statement. This is beacause of a change to the specification of block statements in ES6 which means that each block has its own lexical environment. In the above example, a new lexical environment is created when the block (the body of the for statement) is evaluated.

Similarly we can also declare block-scope variables by using const statement which actually declares constants. Here is an example to understand the behavior

var a; // a === undefined

const b; // SyntaxError: const declarations must have an initializer
Variables defined using const statement must have an initializer. Variable in above example throws similar error while we tried to declare it without initial value.

const b = 10; // b === 10

b = 20; // SyntaxError: Assignment to constant variable

Initial value of a const variable cannot be modified. Block scoped variables defined with let and const have similar behavior except to the fact that variables declared with const are read only and they must have an initializer while declaration.

Good Practices
It is very good practice to always declare and define your variables rather than depending on Javascript behaviour to get the variable(no var) automatically defined in the global scope. This may lead to a very confusing code in near future when the size grows.
Also always declare your variables on the top of your current scope. Do not declare a lot of global variables. Always give preferences to local variable wherever possible.

Hope you liked reading my post. I would love to get your valuable feedback in for of of comments.

Happy coding!




Related

technology 5461065999736212693

Post a Comment

  1. Excellent article. Keep writing buddy. I will bookmarking your blog.

    ReplyDelete
  2. Good illustration. Keep it up.

    ReplyDelete
  3. Very good article thanks

    ReplyDelete
  4. Typo with the "JavaScript does not have block level scope" code, it should be


    for (var i = 0; i < 5; i++)

    ReplyDelete
  5. Something to point out , is that try ... catch block binds a caught exception to a variable that is scoped just to the catch block .

    Example :


    function scope_test(){
    var x = "something";
    var result = [];
    result.push(x);

    try{
    throw "exception";
    } catch (x){
    x = "Catched!";
    }

    result.push(x);
    return result;
    }

    scope_test(); // ["something","something"]

    ReplyDelete
  6. I gather the impression from reading this article that you too don't fully understand the topic you are writing about.

    ReplyDelete
  7. The article is quite explanatory, i think you you should re-read the article.

    ReplyDelete
  8. I think you didn't read it properly. I found this article very useful. It is very clear and to the point with really good examples

    ReplyDelete
  9. White text on black background isn't that readable to some of us =(

    ReplyDelete
  10. I'm embarrassed to admit it, but I didn't know Javascript scoping worked that way at all. Thank you!

    ReplyDelete
  11. Thanks for pointing it out. I have done the correction.

    ReplyDelete
  12. Thanks. Great you liked reading the article. This encourages me to continue writing.

    ReplyDelete
  13. Thanks for the appreciation buddy.

    ReplyDelete
  14. Thanks buddy. Feeling great you loved my post. I will keep blogging for sure.

    ReplyDelete
  15. I would love to hear the feedback in details. That will definitely help me to get better.

    ReplyDelete
  16. No issues buddy. You are never too late when its about gaining something. That's how you step ahead. Same applies to me. I keep reading to boost up my concepts.

    ReplyDelete
  17. I didn't get you. Can you please provide more information on this. We have tested on various browsers and devices. We are still unable to identify the issue. I would appreciate if anyone could add up to this where the issue persist.

    ReplyDelete
  18. Have you ever consider the magnitude of problems switching from Windows to Linux? Most XP-users have tons of programs which will be rendered useless. It will be hard to find programs with the same functionality in Linux. Then there´s the learning curve. I would guess that it will take my company at least 9 months to come up to speed after a switch to a new (different) OS. Just a thought. Anyway, I'm going for Windows 7.

    ReplyDelete

emo-but-icon

Translate

 

Recent Posts

comments

Recent Comments Widget

Join Us

 

Sponsored By

Recommended for you

get social

item