68

I've reading scope chain in Javascript but it didn't make any sense to me, could any one tell me what is scope chain and how it works with a graphic or something even an idiot can understand. I googled it but I didn't find something comprehensible :(

Neeraj Kumar
  • 771
  • 2
  • 16
  • 37
Tarik
  • 79,711
  • 83
  • 236
  • 349

6 Answers6

73

To understand the scope chain you must know how closures work.

A closure is formed when you nest functions, inner functions can refer to the variables present in their outer enclosing functions even after their parent functions have already executed.

JavaScript resolves identifiers within a particular context by traversing up the scope chain, moving from locally to globally.

Consider this example with three nested functions:

var currentScope = 0; // global scope
(function () {
  var currentScope = 1, one = 'scope1';
  alert(currentScope);
  (function () {
    var currentScope = 2, two = 'scope2';
    alert(currentScope);
    (function () {
      var currentScope = 3, three = 'scope3';
      alert(currentScope);
      alert(one + two + three); // climb up the scope chain to get one and two
    }());
  }());
}());

Recommended reads:

Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 1
    So, currentScope 3 will override the currentScope 1 value ? – Tarik Sep 27 '09 at 20:42
  • 24
    @Aaron Not override, but **shadow**. – kangax Sep 27 '09 at 20:44
  • 5
    @Aaron, exactly as @kangax says, within the scope of the *third* function the `currentScope` variables declared on the *second, first and global* scopes will be simply *shadowed* or *hidden*, their value will remain intact on the outer closures, since in the third function, you are declaring a **new** `currentScope` variable that resides in that scope, and for that when you access it there, it will be the first at the scope chain. – Christian C. Salvadó Sep 27 '09 at 21:45
  • 1
    But what if I want to access scopeChain in the second function then will it be 3 since the place where variables defined rather than place the variables get executed ? – Tarik Sep 28 '09 at 04:18
  • 1
    I think I got it, It is different than what I thought before.Let me tell you what I understood : every variables gets the value actually from where it is defined rather than executed so the functions have their own scope and e.g. currentScope 3 hides the value of currentScope 2 because they are defined in different scopes but if I want to access currentScope in the second functions it would return 2 because currentScope 3 is only effective in third function, it only effects the variables defined in its own scope. That makes sense now. So if I don't use var, then I happen to define a global one – Tarik Sep 28 '09 at 04:36
  • And I actually run your code here and it showed me the right thing : http://jsbin.com/afebi/edit thanks..... – Tarik Sep 28 '09 at 04:38
  • 1
    And by doing that, I hide my variables which means they are like private variables in C#. – Tarik Sep 28 '09 at 04:41
  • 1
    @Aaron, a better example on C# would be name hiding through nesting (http://is.gd/3JUQs) or through inheritance (http://is.gd/3JUVr) – Christian C. Salvadó Sep 28 '09 at 06:36
  • This is one of the best explanations I've seen. – samcozmid Dec 10 '17 at 02:50
  • I just learned about this here: https://www.coursera.org/learn/html-css-javascript-for-web-developers/lecture/4tOjk/lecture-41-part-1-defining-variables-function-and-scope What other languages have this trait? Python? – mLstudent33 Jul 14 '20 at 05:51
  • hi @Christian C. Salvadó + 1. "within the scope of the third function the currentScope variables declared on the second, first and global scopes will be simply shadowed or hidden, their value will remain intact on the outer closures, since in the third function, you are declaring a new currentScope variable that resides in that scope, and for that when you access it there, it will be the first at the scope chain" - This also applies to the prototype chain, **any** operation affects only the object itself, **never the prototype chain**, right? –  Jan 28 '23 at 12:12
  • @kangax "Not override, but shadow" - how it happens in the prototype chain, right? –  Jan 28 '23 at 12:13
21

Any function call in ECMAScript ( core language that JS is based on ) produces a separate execution context, which run individually from one another. Inside of each execution context, this refers to the object in question, defaulting to whatever the function is attached to.

function foo() {
    alert(this===window)
}

Would alert true, because the window is the object which owns the 'foo' method. Any variables defined in a function become accessed through that function's unique scope chain, environment.

function world() {
    var name = 'global';
    alert(name)
}

would alert 'global' obviously.

function world() {
    var name = 'global';
    (function() {
        var name = 'country';
        alert(name)
    })();
    alert(name)
}

In the latest example, when the first alert is invoked, Javascript determines that in the scope chain of the inner function that the identifier name is defined, so it doesn't have to look up the scope chain to grab it.

In the second alert invocation, name is also defined in the same context and alerts 'global';

function world() {
    var name = 'global';
    (function() { alert(name) })();
}

In this example, the name identifier is not defined in the same context and thus it has to travel up the scope chain to the outer function where name is defined, and it alerts global.

Reference:

Roy Prins
  • 2,790
  • 2
  • 28
  • 47
meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
6

I know it's an old post but it is still helpful for developers. I wanted to do it little different way as it would be more friendly for beginners to understand scope chaining. Here is my modified version of code:

var currentScope = 0; // global scope
function a () {
   var currentScope = 1, one = 'scope1';
   alert(currentScope);

  function b () {
      var currentScope = 2, two = 'scope2';
      alert(currentScope);

      function c () {
         var currentScope = 3, three = 'scope3';
         alert(currentScope);
  alert(one + two + three); // climb up the scope chain to get one and two
     }
     c();
  }
  b();
}
a();
JVM
  • 946
  • 1
  • 10
  • 23
  • Regarding -1, I want to know if my version is not at all helpful for a "idiot" to understand (as the original question states). – JVM Mar 17 '16 at 20:16
  • 1
    I don't think your comment is useless. Although it is actually the same as the very first example, but I do agree that a lot of Immediately Invoked Function Expressions in the first example could be embarrassing to Javascript beginners. However, I would make function calls in the beginning of the functions not in the end as it would make the code more readable IMHO. – volk Sep 22 '16 at 17:44
6

Summary:

The scope chain is used to resolve the value of variable names in javascript. Without a scope chain the Javascript engine wouldn't know which value to pick for a certain variable name if there are multiple defined at different scopes. Scope chain in javascript is lexically defined, which means that we can see what the scope chain will be by looking at the code.

At the top of the scope chain is the global scope, which is the window object in the browser (global in NodeJS). Besides from the global scope, functions have their own scoping of variables. The scope chain can be determined by looking at where functions are defined.

When resolving a variable, inner functions first look at their own scope. If the variable cannot be found in its own scope it will climb up the scope chain and looks for the variable name in the environment where the function was defined. This look like this:

Scope chain javascript

So in our image example when innerFoo uses the variable bar it first tries to find it within the scope of the innerFoo (code within function body). Then when it doesn't find it here it climbs up the scope chain to foo. In foo there is also no variable which is named bar. Therefore, it will climb up the scope chain and now look in the global scope. In the global scope is a variable named bar with a value of 10 to which bar will be resolved.

Example:

let foo = 1;
let bar = 1;


function test (bar) {
   
   return function innerTestFunc () {
      let foo = 10;
      
      console.log(foo, bar);
    }
  
}

const innerTestFunc1 = test(5);
const innerTestFunc2 = test(20);


innerTestFunc1();  // logs 10, 5

innerTestFunc2();  // logs 10, 20

In the above example we have a function which returns a function. We first store this function in the variables innerTestFunc1 and innerTestFunc2. This creates a closure which is basically a snapshot of the scope chain of the outer environment.

Then when the functions are executed the function requires a value for both the variables foo and bar. The value of foo can be resolved at the level of the innerTestFunc and is 10 for both. 10 is already found in innerFoo, so no need to climb the scope chain for foo.

In the case of the bar variable the function cannot find it in the innerFoo. Therefore, it will climb up the scope chain. It first encounters the variable bar in the function test, therefore it will resolve value of bar to whatever the value is in the test function (5, 20 in our example).

Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
5

This is about closure. You may use variables outer from scope in the inner scope:

function get_inner_scope () {
    var outer = 'Outer variable value';
    return function () {
        alert(outer);
    }
}
f = get_inner_scope();
f(); // alerts Outer variable value

More deatailed info with other samples by first google's link: http://blogs.msdn.com/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx

Anatoliy
  • 29,485
  • 5
  • 46
  • 45
4

Scope chain in Javascript explained in layman terms

Alex is a happy guy,One fine day,walking down the road with his monthly salary in hand gets mugged.

Later he realizes that tomorrow is the last day to pay for his daughters tuition of 1000$.
He runs home,finds his savings of 400$,worries about the rest(600$).The immediate thought that flashes,is to borrow some from his father Mathew.
Mathew,the poor carpenter,devoid from any money sells his inherited bracelet for 300$ and lends it to his son Alex.
Alex having a good reputation in the society,gets the remaining 300$ from a local bank immediately and pays his daughter tuition on time.

Coming back to Scope chain in Javascript:
Alex-A function in javascript
Mathew-The immediate function,Alex is nested in.
Mathews parents-The immediate function Mathew is nested in.
Bank-Global variables.

function Bank() {
    loan=300;
    Mathew();

    function Mathew() {
        mathew=300;
        Alex();

        function Alex() {
            savings:400;
            alert('I need some money');
        }

    }

}

Bank();

Scope chain of Alex at this point looks like: [savings:400]+[mathew:300]+[loan:300];

Sai Chandra
  • 367
  • 2
  • 8