Scope In JavaScript
Where do variables live in JavaScript? Let's learn about Scoping and the Scope Chain in this post.
What is Scoping?
Scoping is a way to organise and access variables. In JavaScript, there is a concept called Lexical Scoping - which is a way of controlling Scope of variables by the placement of functions and blocks in the code.
What is Scope?
Scope is simply the space or environment in which it is declared.
Scope of a variable is a region of the code where the variable can be accessed.
In the case of functions, Scope is the variable environment which is stored in the function's execution context.
There are 3 types of scope -
Global Scope - for all top level code
The variables are declared outside of any function or block.
These variables that are declared in global scope are accessible everywhere in the code.
Function Scope - this type of scope is created each time a function is declared.
Variables declared in this function are only accessible within this function, and not outside of it.
This is also called local scope
function funcScope() { const a = 123 const b = 321 const diff = b - a return diff } console.log(b) // ReferenceError
As can be seen above, trying to access the variable
b
gives aReferenceError
since we are trying to access it outside its scope.It also does not matter what type of function we are using - function declarations, function expressions, arrow functions - all create their own scope.
Block Scope (ES6) - beginning from ES6, blocks can also create scopes. Blocks are created by curly braces in JavaScript, and any variable within these braces is said to be scoped to that particular block.
Blocks are created by
if
statements,for
loops, etc.NOTE: Block scope is only applicable to variables declared with
let
andconst
.var
variables declared within a block are still accessible outside of it too.From ES6 onwards, all functions are also block scoped - only in strict mode.
if(login) { const greet = 'Welcome' } console.log(greet) // ReferenceError
Here, the
if
condition has created a block so scope of the variablegreet
is restricted to this block. Trying to access it outside of the block results in aReferenceError
.
Scope Chain
Let us walk through the below code snippet and examine the scope chain implemented for global and function scopes -
const myName = 'Vinoo' // Global variable
// The below function "first()" is also technically a global variable
// since all functions and function expressions are considered
// variables; but for this code snippet we will consider only variable
// declarations for global scope
const myName = 'Vinoo'
function first() {
const experience = 4
if (experience >= 4) {
var seniorDev = true
}
function second() {
const job = 'Developer'
console.log(`${myName} is a ${experience} years experienced
${job}`)
}
second()
}
first()
As we can see, myName
has global scope and functions first()
and second()
have function scopes set for the respective variables declared in them. However, notice that the variables myName
and age
are being referenced within the function second
- but their scope is supposed to be limited to the function block of second()
right?
This is where the scope chain comes into play - when one scope needs to use variables from another scope, it will "look up" in the scope chain and see if it can be used. This is called the "variable lookup" in the scope chain. In other words, a scope has access to variables declared in the outer scopes. In this case, the function second()
looks outside of its scope to access the variable values from outer scopes - from first()
and the global scope for myName
.
This is also known as Lexical Scope - the ability of an inner function scope to access variables from the parent scope.
NOTE: Scopes simply look up for the variable's value in the scope chain and never actually copy the variables itself to use in their own scopes.
Also, the scope chain only works upward - meaning, only an inner scope can look up the scope chain for variables and not the other way around; an outer scope will never have access to the inner scope variables.
We are now clear with the scope chain implemented for function scopes. However, in the above snippet, line numbers 6 to 8 contain an if
block. Remember, only starting from ES6 implementation, we have block scopes functionality with let
and const
variable declarations. But, we can see in the snippet, we have a variable declared within the if
block with var
.
This means that var
has no block scope - but it is still limited to the function that it is declared within; it has function scope.
let
andconst
are block scoped.
var
is function scoped.
Therefore, in our code snippet - the variable seniorDev
is not scoped to the if
condition within which it is declared; instead, it is scoped to the function first()
. Incidentally, the function second()
can access this since it is declared within the function first()
.
In essence, the below illustration captures the Scope Chain for the above code.
That was it for Scope and Scope Chain in JavaScript! We have given enough lunges for the brain with this topic.
To really get basics right, you should alter the above code snippet and experiment with it by declaring variables in different scopes and tinkering with the flow.
In the next post, we will dive into Hoisting and the this
keyword - thereby working towards cementing our foundational knowledge of how JavaScript works.
See you in the next one ๐
Keep shipping ๐