DEV Community

Prakhar Chauhan
Prakhar Chauhan

Posted on

Scoping and the Scope Chain

Scope and scoping is one the fundamental topics that every Javascript beginner makes mistake on.

Scoping basically answers the question “where can we access a certain variable or function?”

In JS, each function creates a scope - _this is the space or environment in which the variables that it defines are accessible. In other programming languages, scopes can also be created by if/why/for blocks, but that is not the case in JS. Here in JS, the only way to create a new scope is to write a new function - this is very important in JS.

JS uses lexical scoping - this means that a function that is lexically within another function (i.e. written inside another function) gets access to the scope of the outer function/parent function, and with that it gets access to the variables and functions that the parent function defines.

Consider the following code:

var a = 'Hello!';
first();
function first() {
var b = 'Hi!';
second();
function second() {
var c = 'Hey!';
console.log(a + b + c);
}
}
Enter fullscreen mode Exit fullscreen mode

The whole code sits within the global scope and thus has access to the global VO. The code within the “first” function sits in the “first() scope” and has access to the variables and functions defined in the global VO and VO1 associated with the execution context of the first() function. Similarly, the function second() sits in the “second() scope” and has access to the functions and variables from VO2 (associated with the execution context of the “second” function, VO1 and the global VO) due to its lexical positioning within the context of “first” and the global context. This is why it can read the variables a and b despite their definitions being outside of its context.

So the global scope contains a, the “first() scope” contains a and b, and the “second() scope” contains a, b and c. This is what we refer to as the scope chain. When JS does not find a variable within its immediate execution context, it moves up the scope chain in search of the variable. We only return an error when JS does not find a variable anywhere.

Note that this does not work backwards. The global scope will not have access to the variables b or c unless they are returned from their functions. Locally scoped variables are not visible to their
parent scopes. The scope chain only works “upwards”. How this works is that in the creation phase of each execution context object, the object gets the exact scope chain, which is basically all of the variable objects that the execution context has access
to.

In our above example, in the second scope we have access to the variable objects of the second
function, the first function and the global variable object.

Image description

Here is a visual example of the difference between the execution stack and the scope chain. Note that we indent scopes to show which are contained in which “levels”. The third() scope here is contained within the global scope but since third() is not contained lexically within second() or first() then it does not have access to the scope of these functions - and thus doesn’t contain its variables, even though the third() function is called within the second() function.

Execution contexts store the scope chain of each function in the variable object, but they do not have an effect on the scope chain itself. These are inherently different concepts. Note that the second() function can still call the third() function because it has access to the global scope, even thought the third() function can not read the variables b and c which are defined outside
of its scope.

Discussion (0)