Starting out as a JavaScript Developer, understanding the concept of scope in JavaScript was pretty much complex for me. This article is for those who are finding it hard to grasp JavaScript scope. Here is a comprehensive explanation on JavaScript's scoping system.
Scope
Scope in JavaScript defines where variables, arguments and objects can be accessed in your program code. There are two kinds of scopes in JavaScript - Global scope and Local Scope.
Global Scope
Any variable declared in the Global scope can be accessed and altered anywhere in the program. Global scope is where you are when you start a program and it is first executed before any other function. Global variables (variables written in the Global scope) are declared outside of all functions or block/curly braces {}
.
const pet = 'Dog'; // global variable
const saySomething = () => {
console.log(`I have a ${pet}`)
}
saySomething()
Ironically, using Global scope is not really encouraged in JavaScript. This is as a result of possible naming conflict in your program (two or more variables having the same name). Using let
and const
to declare variables would throw error whenever there is a name conflict.
let saySomething = "Hello";
let saySomething = "Hi"
console.log(saySomething) // throws an error
However, when declaring your variables with var
, the second variable will overwrite the first variable.
var saySomething = "Hello";
var saySomething = "Hi"
console.log(saySomething) // Prints "Hi"
This approach is also not recommended, as this could make your program develop a bug which can be hard to find and debug.
Local Scope
In Local scope, variables are declared within a function or a block { }
, and can only be used in that part of the code.
There two kinds of local scope: Block scope and Function scope.
Block scope
In Block scope, variables are declared using let
or const
in curly braces { }
. These variables are accessible only within the curly braces.
{
const saySomething = "Hello"
console.log(saySomething) // prints "Hello"
}
console.log(saySomething) // ReferenceError: saySomething is not defined
Normally, block is part of a control flow statement (such as if
statement), but having a standalone block is still valid.
Function scope
In function scope, variables declared in a function, are only accessible within that function.
function greet() {
let saySomething = "Hi"
console.log(saySomething)
}
greet() // Hi
console.log(saySomething) // ReferenceError: saySomething is not defined
Lexical Scoping
Wherever you define a function from, variables in that scope are also valid in the function scope. Whereas variables defined in the function scope will not be accessible outside the function. Lexical scoping is a conventional scoping mechanism in JavaScript, where code runs from top to bottom. By glancing through your code, we can actually tell (though not always very obvious) what variables are in scope.
Example
let y = 0
if(true){
var x = 1;
console.log(y); // y prints 0
}
function result() {
let y = 2;
if(true){
console.log(x); // x prints 1
let y = 3
console.log(y) // y prints 3
}
if(true){
console.log(y); // y prints 2
}
}
console.log(y) // y prints 0
result()
It's quite confusing right? Don't worry it's not as complex as you think. Lets break it down.
Look closely, y
is assigned the value 0. The if
statement is then run, assigning x
the value 1, before logging y
to the console. Before JavaScript calls the result
function, y
is logged again to the console. In the function scope, y
is assigned a new value 2. Within the function scope, the first if
statement block runs, logs x
to the console, assigns a new value 3 to y
and finally logs y
. The second if
statement block runs, and logs y
to the console. You should know that the variable y
may have the same name, but they are actually different. This concept is called Variable Masking
Variable Masking
Variable masking (also known as Variable shadowing) is whereby variables having the same name can be specified at multiple nested scope. These variables may have the same name but are actually different. Let's consider this example
{
let pet = "Dog"
console.log(pet) // Dog
{
let pet = "Cat"
console.log(pet) // Cat
}
console.log(pet)
}
From the example, the pet
variable in the inner block is distinct from the pet
variable in the outer block, hence they produce different results. This is known as masking (or shadowing).
Conclusion
JavaScript scope is a very important concept to know in JavaScript programming. I hope from reading this article, you got a better understanding of JavaScript Scope. If you do, kindly leave a like or comment and share with friends. Got any doubt or question, leave a comment as well, I'll be glad to help ๐