I can’t tell how often I met Javascript developers who have been building web applications for several years. Yet, they still don’t fully understand some of the basic programming concepts. And this lack of understanding comes back to bite them in the form of needlessly wasting countless hours on solving confusing bugs. Javascript variable scope is one of these concepts. A proper understanding of variable scope in Javascript will save you a lot of time and effort on your future projects.
What is Variable Scope
In programming, the scope of a variable refers to the part of the code where a variable is accessible. In JavaScript, the scope of a variable is determined by its location within the source code, and nested blocks of code have different scopes.
Difference between Local and Global Variables
JavaScript has two types of variable scopes: global and local.
- Local Variables
A local variable is a variable declared inside a block or a function. It is only accessible within the function or block it’s declared in. Here’s an example:
function greet() {
let greeting = 'Hello, World!';
console.log(greeting); // Output: 'Hello, World!'
}
console.log(greeting); // Error: greeting is not defined
In the above code, greeting
is a local variable defined inside the greet
function. It’s not accessible outside this function.
- Global Variables
On the other hand, a global variable is one that’s declared outside of any function or block. It’s accessible from any part of the code. Let’s look at an example:
let greeting = 'Hello, World!';
function greet() {
console.log(greeting); // Output: 'Hello, World!'
}
console.log(greeting); // Output: 'Hello, World!'
Here, greeting
is a global variable because it’s declared outside the greet
function, making it accessible from anywhere in the code.
Use of var
, let
, and const
var
As I explained in my post about Javascript variables and data types, you can declare variables and constants using var
, let
, and const
keywords. Each has a different impact on the scope of the variable.
var
: Variables declared withvar
are function-scoped, meaning they are accessible in the entire function they are declared in, even if they are declared in a sub-block inside this function.let
: Variables declared withlet
are block-scoped, meaning they exist only within the block they’re declared in.const
: Similar tolet
, constants declared withconst
are also block-scoped. However, once assigned,const
variables can’t be reassigned.
So what’s the difference between function-scoped and block-scoped you ask? Let’s take the following piece of code as an example:
// Example with var
function exampleVar() {
for (var i = 0; i < 5; i++) {
console.log("Inside the loop with var: " + i);
}
console.log("Outside the loop with var: " + i);
}
exampleVar();
// Example with let
function exampleLet() {
for (let j = 0; j < 5; j++) {
console.log("Inside the loop with let: " + j);
}
console.log("Outside the loop with let: " + j);
}
exampleLet();
The code above will produce the following output:
Inside the loop with var: 0
Inside the loop with var: 1
Inside the loop with var: 2
Inside the loop with var: 3
Inside the loop with var: 4
Outside the loop with var: 5
Inside the loop with let: 0
Inside the loop with let: 1
Inside the loop with let: 2
Inside the loop with let: 3
Inside the loop with let: 4
ReferenceError: j is not defined
In the first function, we declared i
using var
inside a for
loop block, but we were still able to access the value of i
outside of the for
loop block on line 6 because var
is function-scoped.
In the second function, however, we declared j
using let
inside the for
loop block. Because let
is block-scoped, we are unable to access it on line 16 because it’s outside the for
loop. Even though we’re calling it from inside the exampleLet()
function.
Hoisting Concept
“Hoisting” is a JavaScript mechanism where variables and function declarations are moved to the top of their containing scope before interpretation. However, only the declarations are hoisted, not initializations. Understanding hoisting is key to understanding how JavaScript interprets our code.
console.log(x); // Output: undefined
var x = 5;
In this example, the JavaScript interpreter hoists the declaration of the x
variable to the top of the code. So, when we try to log x
before we’ve assigned a value to it, it returns undefined
instead of throwing an error.
Note that this would only work using var
. If you were to attempt the same by declaring a variable or a constant using let
or const
, you would get a reference error. This is because variables and constants declared with let
and const
are hoisted but never initialized. So they are considered in a temporal dead zone until they are declared.
I explained JavaScript hoisting in the article for the sake of completeness, but that doesn’t mean I recommend relying on it. let
is currently the recommended way of declaring variables, so it’s best to use it and ignore the capabilities of Javascript hoisting.
Closure Concept
A “closure” in JavaScript occurs when an inner function has access to the outer scope of its enclosing function. This concept is directly linked to variable scope and is fundamental to writing effective JavaScript code.
function greet() {
let greeting = 'Hello, World!';
return function() {
console.log(greeting);
}
}
let greetHello = greet();
greetHello(); // Output: 'Hello, World!'
In this example, the greet()
function doesn’t return a simple value, but it returns a function that can be invoked. The inner function retains access to the greeting
variable even after the outer function has finished execution.
This is a very basic example of a closure, and it might not be apparent yet how this can be useful. But closures are used in abundance in all kinds of Javascript applications, and understanding how the variable scope works with them is essential for making the most out of them.
Final Notes & Further Readings
I tried my best to include everything you need to know about javascript variable scope in this post. A proper understanding of variable scope, the use var
, let
, and const
, as well as hoisting and closures will give you a solid basis on which you can continue developing your javascript skills. Keep coding, and don’t forget to try everything you learn in your own code editor!