JS 103: Understanding JavaScript Hoisting and Scoping Rules

In JavaScript, hoisting and scoping are two fundamental concepts that every developer should understand in order to write efficient and maintainable code. Hoisting refers to the way JavaScript moves variable and function declarations to the top of their scope, which can sometimes lead to unexpected behavior. Scoping, on the other hand, determines the accessibility of variables and functions within a program and is a key aspect of organizing and structuring code. In this blog, we will dive into these concepts and explore how they work, their implications, and best practices for using them in your own projects. Whether you are a beginner or an experienced developer, this blog will provide valuable insights into hoisting and scoping in JavaScript.
Introduction to Hoisting in JavaScript:
Definition of Hoisting:
Hoisting is a term used in JavaScript to describe the behavior of moving variable and function declarations to the top of their scope. In other words, the declarations are effectively “hoisted” to the top of the code block, giving them a higher level of accessibility and making them available for use before the code is executed. This behavior can lead to some confusion for developers, as variables may appear to be accessible before they are actually declared. It’s important to understand hoisting in order to write clear and predictable code in JavaScript.
How Hoisting Works in JavaScript:
Hoisting in JavaScript works by moving variable and function declarations to the top of their scope, but it doesn’t actually initialize the variables. For example, consider the following code:

In this code, the declaration var x
is hoisted to the top of the scope, but the assignment x = 10
is not. When the code is executed, it will log undefined
to the console instead of throwing a ReferenceError, which would occur if the variable had not been declared at all. This is because hoisting only moves the declaration and not the assignment.
Function declarations are also hoisted in a similar manner. For example:

In this code, the function foo
is declared and hoisted to the top of the scope, making it available for use before the code is executed. When the code is run, it will log "Hello, World!"
to the console, demonstrating that the function is available for use before it is declared.
It’s important to note that the behavior of hoisting can sometimes lead to unexpected results, especially when working with variables declared with the var
keyword. To avoid these issues, it's best to use the let
and const
keywords when declaring variables in modern JavaScript, as these keywords have different scoping rules that are less prone to confusion.
Understanding JavaScript Scoping:
Global and Local Scopes:
In JavaScript, scopes define the accessibility of variables and functions within a program. There are two main types of scopes in JavaScript: global scope and local scope.
The global scope is the highest level of scope in a program and encompasses the entire codebase. Variables and functions declared within the global scope are accessible from anywhere in the program. For example:

In this code, the variable x
is declared in the global scope and is accessible from within the function foo
.
Local scope, on the other hand, is created within a code block, such as a function, and is only accessible from within that block. For example:

In this code, the variable x
is declared within the function foo
and is only accessible from within that function. When we try to access x
from outside the function, it throws a ReferenceError
, demonstrating that the variable is only accessible within its local scope.
It’s important to understand the distinction between global and local scopes in JavaScript to write clear and maintainable code and avoid issues such as variable name collisions and unintended access to variables.
Block-Level Scoping:
Block-level scoping is a type of scoping in JavaScript that is specific to variables declared with the let
and const
keywords. In contrast to the traditional scoping rules of JavaScript, block-level scoping restricts the accessibility of variables to the block in which they are declared.
For example:

In this code, the variable x
is declared within a block created by the if
statement and is only accessible from within that block. When we try to access x
from outside the block, it throws a ReferenceError
, demonstrating that the variable is only accessible within its block-level scope.
Block-level scoping is a feature introduced in ECMAScript 6 (ES6) and is considered a more modern and cleaner way of managing variables in JavaScript. It helps to avoid issues such as unintended access to variables and provides a clearer way to structure code. It’s recommended to use let
and const
instead of var
when declaring variables in modern JavaScript in order to take advantage of block-level scoping.
The Interplay of Hoisting and Scoping:
Understanding Variable Declarations and Assignments:
In JavaScript, variables are declared using the keywords var
, let
, and const
. The way these keywords behave with regard to hoisting and scoping has changed over time with the introduction of ECMAScript 6 (ES6), and it's important to understand the differences between them.
var
is the original way of declaring variables in JavaScript and is function scoped. This means that variables declared with var
are accessible within the function in which they are declared, and are hoisted to the top of their scope. For example:

In this code, the declaration var x
is hoisted to the top of the function scope, making it accessible before the code is executed. When the function is executed, it logs 10
into the console.
let
and const
were introduced in ES6 as a way to declare variables with block-level scoping. Unlike var
, variables declared with let
and const
are not hoisted to the top of their scope and are only accessible within the block in which they are declared. For example:

In this code, the declaration let x
is block-scoped and is only accessible from within the block created by the if
statement. When we try to access x
it from outside the block, it throws a ReferenceError
, demonstrating that the variable is only accessible within its block-level scope.
The const
keyword is similar to let
, but it creates a read-only reference to a value. This means that variables declared with const
cannot be reassigned after they are declared.
It’s important to understand the differences between var
, let
, and const
when declaring variables in JavaScript, as these differences can have a significant impact on the behavior of your code. In general, it's recommended to use let
and const
instead of var
when declaring variables, as they provide block-level scoping and can help to avoid unexpected results.
Best Practices for Using Hoisting and Scoping in JavaScript:
Tips for Writing Clean and Maintainable Code:
Writing clean and maintainable code that takes hoisting into account is an important part of JavaScript development. Here are a few tips to help you write clean and maintainable code that correctly handles hoisting:
- Use
let
andconst
overvar
: As discussed earlier,let
andconst
provide block-level scoping and do not hoist assignments, making it easier to understand and debug your code. - Initialize variables before use: Since hoisting only moves the declaration and not the assignment, it’s important to initialize variables before using them. If a variable is not initialized before use, it will have a value of
undefined
and can lead to unexpected results. - Avoid declaring variables with the same name in different scopes: Declaring variables with the same name in different scopes can lead to naming collisions and confusion. To avoid this, use descriptive and meaningful names that clearly communicate the purpose of the variable.
- Use functional scoping when appropriate: Function scoping can be useful when you want to limit the accessibility of variables within a specific function. This can help prevent naming collisions and make it easier to understand the behavior of your code.
- Avoid using global variables: Global variables can be accessed from anywhere in your code, making it harder to understand the behavior of your code and debug issues. Instead, use functional or block-level scoping to limit the accessibility of variables to only where they are needed.
Common Mistakes to Avoid:
When writing JavaScript code that involves hoisting, it’s important to be aware of the common mistakes that can occur. Here are a few common mistakes to avoid:
- Relying on hoisting for variable assignments: As mentioned earlier, hoisting only moves the declaration of a variable to the top of its scope, not the assignment. Relying on hoisting for variable assignments can lead to unexpected results and should be avoided.
- Declaring variables with the same name in different scopes: Declaring variables with the same name in different scopes can lead to naming collisions and make it difficult to understand the behavior of your code. To avoid this, use descriptive and meaningful names that clearly communicate the purpose of the variable.
- Overusing global variables: Overusing global variables can make it difficult to understand the behavior of your code and debug issues. Instead, use functional or block-level scoping to limit the accessibility of variables to only where they are needed.
- Confusing the behavior of
var
withlet
andconst
:var
is function scoped and hoists both the declaration and the assignment to the top of its scope, whilelet
andconst
provide block-level scoping and only hoist the declaration. Confusing the behavior of these keywords can lead to unexpected results. - Forgetting to initialize variables before use: As discussed earlier, hoisting only moves the declaration of a variable to the top of its scope, not the assignment. If a variable is not initialized before use, it will have a value of
undefined
and can lead to unexpected results.
By avoiding these common mistakes, you can write JavaScript code that correctly handles hoisting and ensures that your code is clean, maintainable, and easy to understand.
Conclusion:
In conclusion, hoisting is an important concept in JavaScript that refers to the way variable and function declarations are moved to the top of their respective scopes. Understanding hoisting can help you write clean and maintainable code that is easy to understand and debug.
Here are the key points to remember about hoisting:
- Hoisting only moves the declaration of a variable or function to the top of its scope, not the assignment.
- Variables declared with
var
are function scoped and hoist both the declaration and the assignment to the top of the scope, while variables declared withlet
andconst
provide block-level scoping and only hoist the declaration. - It’s important to initialize variables before use, as hoisting only moves the declaration and not the assignment.
- To write clean and maintainable code that takes hoisting into account, it’s important to use descriptive and meaningful names, use
let
andconst
overvar
, use functional scoping when appropriate, and avoid using global variables.
By understanding these key points and avoiding common mistakes, you can write JavaScript code that correctly handles hoisting and ensures that your code is clean, maintainable, and easy to understand.
Connect with me:
Twitter
Portfolio
LinkedIn
Regards,
Ahmad Mustafeen,
Software Engineer at Geeks of Kolachi