JavaScript is a flexible and powerful programming language, but it has some tricky parts that can confuse even experienced developers. One of these tricky parts is variable scope, which is how and where you can use variables in your code. It’s important to understand how var
, let
, and const
work to write clean and error-free code. In this blog post, we’ll explain these keywords with practical examples.
Developers often assume let and const variables are not hoisted due to the error thrown when accessing them before initialization. However, they are hoisted but remain uninitialized, holding the value uninitialized
. To learn more about variable declaration and initialization, I recommend referring to my previous blog post titled JavaScript Execution – What Happens Behind the scenes.
What is Variable Scope?
Variable scope refers to the context in which a variable is defined and accessible. JavaScript has two main types of scopes:
- Global Scope: Variables declared outside of any function are in the global scope and can be accessed from anywhere in the code.
- Local Scope: Variables declared within a function are in the local scope and can only be accessed within that function.
- Block scope: A variable is only accessible within the block (denoted by curly braces
{}
) in which it is declared.
Let’s dive into how var
, let
, and const
handle scoping differently.
The var Keyword
The var keyword is global and function-scoped, meaning that variables declared with var are accessible throughout the entire function in which they are declared or accessible throughout the program if they are globally declared.
The let Keyword
The let
keyword was introduced in ECMAScript 6 (ES6) and provides block-level scope. This means that variables declared with let
are only accessible within the block they are defined in.
The const Keyword
The const
keyword also provides block-level scope but is used for variables that should not be reassigned after their initial assignment. It’s important to note that while the variable cannot be reassigned, the value it holds (if it’s an object or array) can still be modified.
Feature | var | let | const |
---|---|---|---|
Global scope | Yes | No | No |
Function scope | Yes | Yes | Yes |
Block scope | No | Yes | Yes |
Can reassigned | Yes | Yes | No |
Hoisting | Top of execution with value undefined | hoisted but not initialized with value uninitialized. The variables are not initialized until the code execution. | hoisted but not initialized with value uninitialized. The variables are not initialized until the code execution. |
How do you assign default values to variables?
You can assign default values to variables using the ||
(logical OR) operator. it provides a simple way to fall back to a default value if the original variable is falsy (i.e., undefined
, null
, false
, 0
, NaN
, or an empty string ""
).
let myVar = 0; // 0 is falsy
let defaultVar = 50;
// Using the logical OR operator
let result = myVar || defaultVar;
console.log(result); // 50
Lexical scoping:
JavaScript follows a concept called lexical scoping or static scoping. This means that when a variable is referenced in a certain scope, JavaScript will look for the variable declaration in the current scope. If it doesn’t find it there, it will move up to the parent scope, and continue this process until it reaches the global scope or finds the variable.
Practical Examples-What will be the output
Let’s look at some more examples to solidify our understanding of how var
, let
, and const
work in different scopes.
function checkScope() {
let x = 10;
if (true) {
let x = 20;
console.log(x); // ?
}
console.log(x); // ?
}
checkScope();
//Answer:
20
10
Explanation: In the function checkScope
, let x = 10;
creates a block scope for the checkScope
function. Inside the if (true)
block, let x = 20;
creates a block scope only for the if
statement. Thus, the console.log(x)
on line 5 outputs 20
, and the console.log(x)
on line 7 outputs 10
.
If we declare a variable with the
let
keyword within curly braces{}
, it will be scoped to that specific block.
function checkScope() {
let x = 10;
if (true) {
console.log(x); // ?
let x = 20;
console.log(x); // ?
}
console.log(x); // ?
}
checkScope();
//Answer:
Uncaught ReferenceError: Cannot access 'x' before initialization - line 4
Explanation: The first console.log(x)
in the if
block would cause a ReferenceError
because x
is in the temporal dead zone until its declaration. The ReferenceError
occurs in the execution phase,
In JavaScript, variable declarations using
let
andconst
are hoisted to the top of their block scope during the creation phase, but they are not initialized until the execution phase reaches the actual line of code where the declaration occurs. This period between the start of the block and the line where the variable is declared is called the “temporal dead zone” (TDZ).
To learn more about variable declaration and initialization, please refer to my previous blog post JavaScript Execution – What Happens Behind the scenes
function checkScope() {
var x = 10;
if (true) {
console.log(x); // ?
var x = 20;
console.log(x); // ?
}
console.log(x); // ?
}
checkScope();
//Answer:
10
20
20
Explanation: The var
keyword is function-scoped and does not respect block-level scope. Therefore, on line 4, console.log(x);
will output 10
. On line 5, we are re-declaring the same variable with the value 20
, so console.log(x);
on line 6 will output 20
. Due to function scope, the value 20
remains in the variable, so console.log(x);
on line 8 will also output 20
.
function checkScope() {
let x = 10;
if (true) {
var x = 5;
console.log(x); // ?
}
console.log(x); // ?
}
checkScope();
//Answer:
Uncaught SyntaxError: Identifier 'x' has already been declared
Explanation: The error occurs because the var
keyword does not respect block-level scope when redeclaring a variable that has been declared using let
within the same block.
let x = 10;
declares x
within the function scope. Inside the if
block, var x = 5;
attempts to redeclare x
, which has already been declared using let
within the same block. This action causes the SyntaxError.
What if we changed the var
keyword to let
and let
to var
?
function checkScope() {
var x = 10;
if (true) {
let x = 5;
console.log(x); // ?
}
console.log(x); // ?
}
checkScope();
//Answer:
5
10
Explanation: var x = 10;
is function-scoped, while let x = 5;
within the if
block is block-scoped. Thus, the program executes without errors, producing output:
Let’s delve deeper into how const
behaves with various operations.
const a = 5;
a = 10;
//output:
TypeError: Assignment to constant variable.
Explanation: In JavaScript, when you declare a variable with const, its binding cannot be reassigned.
const b = {c:10};
b.c = 5;
console.log(b.c); // ?
//output:
5
Explanation: In JavaScript, when you declare an object or an array using const
, it means you cannot reassign the variable itself to a different object or array. However, the properties and elements within them can still be modified. This behavior is because const
creates a constant reference to the object or array, not to its contents.
const x = {y:10};
x.z = 10;
console.log(x.z); // ?
console.log(x); // ?
//output:
10
{y:10,z:10}
Explanation: In JavaScript, for objects and arrays, the properties and elements within them can still be modified.
const x1 = {y:10};
x1 = {y:10};
//output:
TypeError: Assignment to constant variable.
Explanation: In JavaScript, when you declare a variable with const, its binding cannot be reassigned.
const colors = ['red', 'green', 'blue'];
colors.push('yellow');
console.log(colors);
// Output:
['red', 'green', 'blue', 'yellow']
Explanation: In JavaScript, for objects and arrays, the properties and elements within them can still be modified.
const greet = () => {
console.log('Hello!');
};
greet();
//Output:
Hello!
Explanation: The use of const in this context prevents the variable greet from being reassigned to a different function or value. Therefore, attempting to override or reassign greet to a different function would result in an error.
You can try the above examples here in the CodePen window.
Here is the video on Variable Scope that you can refer and share.