Let's start...
What is Scope?
The scope is the region where a variable can be accessed by its identifier name.
Let's look into the examples:
Example-1:
const name = 'Akshara' //Global Scope
console.log(name) //Prints Akshara
Example-2:
const name = 'Akshara'
function greetings(){
const greet = `Welcome ${name}` //name is accessible because defined in parent's scope i.e Global scope
//greet variable is defined in function's(greetings) scope
console.log(greet) //Prints Welcome Akshara
}
greetings()
console.log(greet) //Reference Error -> variable greetings is not defined in outer scope
The scope is defined as a set of rules by which the engine finds the variable by its identifier name. Scopes are nested in a hierarchy, so that child's scope has access to the parent's scope but not vice-versa.
Types Of Scopes
Global Scope
Variables declared are not inside the function, block or module and can be accessed from anywhere in the program are defined in Global Scope.
Example-1: //Consider this to be index.js file const totalPrice = 3999 const discountedPrice = 599 const finalPrice = totalPrice - discountedPrice //all three variables are declared in Global Scope Example-2: //Another way to declare global variable window.myName = 'Akshara' //Global variable myName
Module Scope
Variables that are declared in a module (file that is exported) are defined in the module scope.
//order.js file export class Order { items: [], price: { total: 0, currency: 'INR' }, calculatePrice: () => console.log("Price is") } //Order variable is accessed in order.js file only until it is //exported from file and imported in another. //index.js file import { Order } from './order.js'
Function Scope
Variables declared (using let, const, var) inside the function body are defined in Function Scope
function selectGenres() { //All three are function scoped variables var Genre1 = 'Comedy' const Genre2 = 'Horror' let Genre3 = 'Action' console.log(Genre1, Genre2, Genre3) // Prints Comedy Horror Action } selectGenres() console.log(Genre1, Genre2, Genre3) // Reference Error, since scope Resolution fails(trying to access function scoped variables in global scope)
Block Scope
Variables declared in a block ( { } curly brackets) are defined in Block Scope.
//var declared variables are not block-scope.Only let and const Example-1: if(true){ let price = 500 console.log(price) } console.log(price) //Reference Error Example-2: if(true) { const pi = 3.17 console.log(pi) } console.log(pi) //Reference Error Example-3: //VAR is not block-scope if(true) { var status = 'confirmed' console.log(status) //confirmed } console.log(status) //Prints confirmed
Scope Chain
Before diving deep into the scope chain, let's understand the nested scope
Consider this example:
function getGifts(numOfGifts){
//Bubble-2
var complementary = numOfGifts + 1
function getHomeDecorItems(numOfHomeDecorItems){
//Bubble-3
console.log(numOfGifts,complementary,numOfHomeDecorItems) //2,3,1
}
getHomeDecorItems(1)
}
getGifts(2) //Bubble-1
Consider this as bubbles:
Bubble-1: This bubble encompasses the global scope and has just one identifier i.e getGifts
Bubble-2: This bubble encompasses the scope of getGifts
function which includes these identifiers complementary
, getHomeDecorItems
, and numOfGifts
Bubble-3: This bubble encompasses the scope of getHomeDecorItems
function which includes only one identifier numOfHomeDecorItems
Now let's see its execution:
When the engine executes the console.log(numOfGifts,numOfHomeDecorItems, complementary)
statement it goes on to find those three variables. Now numOfGifts
is not found in Bubble-3
, so it goes onto the outer bubble i.e. Bubble-2
finds their numOfGifts
. A similar process happens for complementary
variable. numOfHomeDecorItems
variable is found in Bubble-3
itself.
That is what defines the scope chain
Javascript Engine tries to find the variable in the current scope. If it is not found, it will look into the outer scope and this process continues until it reaches global scope.
Scope look-up is stopped at the first match. If the same identifier name is declared at multiple layers of nested scope, the process is defined as shadowing
Errors due to scope
- Reference Error
Reference Error occurs because of scope-resolution failure.
Example:
function doSomething() {
var saySomething = 'Hello-Australia'
console.log(saySomething) //Prints Hello-Australia
}
console.log(saySomething) //Reference Error
Type Error
Type error occurs when a variable value is found i.e. scope-resolution is a success, but you try to perform some impossible operation.
Example-1:
function convertToUpperCase(){
var d=1234
console.log(d.toUpperCase())
}
convertToUpperCase() //Results in type error
Scope Models in JS
Lexical Scope
The lexical or static scope is determined at lexical i.e. compile time.
let numOfIceCreams = 4;
function printNumber() {
console.log(numOfIceCreams);
}
function log() {
let numOfIceCreams = 5;
printNumber();
}
// Prints 4
log();
Here, console.log
will always print 4
no matter where it is called from.
Javascript uses the Lexical scope model.
Dynamic Scope
In Dynamic scope, you search the current scope, if not found, you search in the function that called the local function and so on i.e. call stack.
Consider the same example:
let numOfIceCreams = 4;
function printNumber() {
console.log(numOfIceCreams);
}
function log() {
let numOfIceCreams = 5;
printNumber();
}
// Prints 5
log();
numOfIceCreams
is not found in printNumber()
function scope so it goes into log()
scope to find numOfIceCreams
and hence prints 5.
Conclusion
The scope is a region where a variable can be accessed by its identifier name.
Variables can be declared in Global, local (module, function, block) scope.
The engine performs a look-up in the outer scope until reaches the global scope to find the variable.
Scope resolution failure results in a reference error.
If scope resolution is a success but an impossible operation is executed it results in a type error.
Javascript uses the Lexical scope model.
Congralutions, you made it to end! I hope you learnt something new today