This is a quick note to keep in mind some interesting things about variable scope in JavaScript when declaring variables with let
and const
.
In JavaScript, variables declared with either let
or const
have block scope. Here are some examples:
1
2
3
4
5
{
let a = 1;
}
console.log(a); // Uncaught ReferenceError: a is not defined
This will raise an error because the variable a
that was declared with let
has a block scope and is only accessible from within the {...}
block. Therefore, when we attempt to log the value of a
outside of the block, an error is raised since no a
variable has been defined in that outer scope.
This becomes more apparent when using if...then
blocks. Unlike Ruby, where variables initialized within if...then
blocks are accessible outside of the if...then
block, in JavaScript they are not:
1
2
3
4
5
if (1 === 1) {
let a = 1;
}
console.log(a);
Like the previous example, this code will also raise the same error since the variable a
declared with let
within the if {...}
block has block scope and is not accessible outside of the block.
For comparison, in Ruby, even if the if
statement branch is not evaluated, the variable is initialized with a nil
value and is accessible outside of the if..then
statement:
1
2
3
4
5
6
7
8
if true
a = 1
else
b = 1
end
p a, b # 1, nil
p c # NameError: Undefined local variable or method 'c' for main:Object
The local variable c
above has not been initialized and an error is raised. Whereas, even though only the truthy branch of the if
statement is evaluated, the local variable b
is still initialized to nil
.
As of far as I know now, variables declared in an outer scope in JavaScript seem to be available within inner scopes.
For example:
1
2
3
4
5
let a = 1;
if (1 === 1) {
console.log(a);
}
1
is logged to the console since the truthy branch of the if {...}
will always be evaluated.
Here’s another example, this time showing variable shadowing:
1
2
3
4
5
6
7
let a = 1;
if (1 === 1) {
let a = 2;
}
console.log(a);
This also logs 1
to the console. The second declaration of the a
variable within the if {...}
block shadows the first declaration of the a
variable. Therefore, the second declaration is only accessible from within the if {...}
block. In this case, it’s not being used. Once we evaluate the console.log
statement on line 7, the variable a
that’s in scope at that time has a value of 1
from the let
variable declaration on line 1.
Using const
to declare a variable is similar, but these variables cannot be reassigned like variables declared with let
:
1
2
3
4
5
const A = 1;
if (1 == 1) {
A = 2; // Uncaught TypeError: Assignment to constant variable.
}
Yet, constants can be declared within an inner block scope, like let
, shadowing constants declared in an outer scope:
1
2
3
4
5
6
7
8
const A = 1;
if (1 == 1) {
const A = 2;
console.log(`Value of A in inner scope: ${A}`);
}
console.log(`Value of A in outer scope: ${A}`);
1
2
Value of A in inner scope: 2
Value of A in outer scope: 1
While this may seem simplistic in terms of programming in general, understanding the scope of variables will likely come in handy when debugging more complicated code later on.