惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
AI
AI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
U
Unit 42
Vercel News
Vercel News
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
Microsoft Security Blog
Microsoft Security Blog
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
Martin Fowler
Martin Fowler
博客园 - 【当耐特】
B
Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
F
Full Disclosure
Google DeepMind News
Google DeepMind News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
H
Help Net Security
Recorded Future
Recorded Future
N
News and Events Feed by Topic
雷峰网
雷峰网
V
Vulnerabilities – Threatpost
Schneier on Security
Schneier on Security
aimingoo的专栏
aimingoo的专栏
S
Schneier on Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
O
OpenAI News
Project Zero
Project Zero
罗磊的独立博客
G
GRAHAM CLULEY
腾讯CDC
P
Privacy International News Feed
V
V2EX
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Hugging Face - Blog
Hugging Face - Blog
爱范儿
爱范儿
H
Heimdal Security Blog
L
LINUX DO - 热门话题
Forbes - Security
Forbes - Security
美团技术团队
MongoDB | Blog
MongoDB | Blog
Security Latest
Security Latest
M
MIT News - Artificial intelligence
T
Tor Project blog
Cisco Talos Blog
Cisco Talos Blog
宝玉的分享
宝玉的分享
T
Threat Research - Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog

Dmitri Pavlutin Blog

Pure Functions in JavaScript: A Beginner's Guide Record Type in TypeScript: A Quick Intro How to Write Comments in React: The Good, the Bad and the Ugly 4 Ways to Create an Enum in JavaScript React forwardRef(): How to Pass Refs to Child Components TypeScript Function Types: A Beginner's Guide How to Use v-model to Access Input Values in Vue Mastering Vue refs: From Zero to Hero Environment Variables in JavaScript: process.env 5 Must-Know Differences Between ref() and reactive() in Vue How to Destructure Props in Vue (Composition API) Triangulation in Test-Driven Development How to Use nextTick() in Vue Programming to Interface Vs to Implementation A Smarter JavaScript Mapper: array.flatMap() Array Grouping in JavaScript: Object.groupBy() How to Access ES Module Metadata using import.meta JSON Modules in JavaScript How to Trim Strings in JavaScript TypeScript Function Overloading How to Debounce and Throttle Callbacks in Vue How to Show/Hide Elements in Vue Sparse vs Dense Arrays in JavaScript How to Fill an Array with Initial Values in JavaScript Covariance and Contravariance in TypeScript What are Higher-Order Functions in JavaScript? How to Use TypeScript with React Components Index Signatures in TypeScript How to Use React useReducer() Hook unknown vs any in TypeScript A Guide to React Context and useContext() Hook How to Use Promise.any() 2 Ways to Remove a Property from an Object in JavaScript 'return await promise' vs 'return promise' in JavaScript How to Use Promise.allSettled() How to Use fetch() with JSON JavaScript Promises: then(f,f) vs then(f).catch(f) What is a Promise in JavaScript? How to Use Promise.all() A Simple Guide to Component Props in React Don't Stop Me Now: How to Use React useTransition() hook A Simple Explanation of JavaScript Variables: const, let, var ES Modules Dynamic Import How to Memoize with React.useMemo() How to Cleanup Async Effects in React Why Math.max() Without Arguments Returns -Infinity How to Debounce and Throttle Callbacks in React Don't Confuse Function Expressions and Function Declarations in JavaScript How to Use ES Modules in Node.js Solving a Mystery Behavior of parseInt() in JavaScript How to Use Array Reduce Method in JavaScript 3 Ways to Merge Arrays in JavaScript A Guide to Jotai: the Minimalist React State Management Library The Difference Between Values and References in JavaScript How to Implement a Queue in JavaScript A Helpful Algorithm to Determine "this" value in JavaScript React useRef() Hook Explained in 3 Steps 7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them? How to Greatly Enhance fetch() with the Decorator Pattern 7 Interview Questions on JavaScript Closures. Can You Answer Them? What's a Method in JavaScript? array.sort() Does Not Simply Sort Numbers in JavaScript How to Solve the Infinite Loop of React.useEffect() The New Array Method You'll Enjoy: array.at(index) What's the Difference between DOM Node and Element? Why Promises Are Faster Than setTimeout()? Everything About Callback Functions in JavaScript How React Updates State 5 Mistakes to Avoid When Using React Hooks 5 Best Practices to Write Quality JavaScript Variables Type checking in JavaScript: typeof and instanceof operators 3 Ways to Check if a Variable is Defined in JavaScript React Forms Tutorial: Access Input Values, Validate, Submit Forms Prototypal Inheritance in JavaScript How to Timeout a fetch() Request How to Learn JavaScript If You're a Beginner A Simple Explanation of React.useEffect() A Simple Explanation of JavaScript Iterators How to Use React Controlled Inputs Everything about null in JavaScript How to Use Fetch with async/await Getting Started with Arrow Functions in JavaScript An Interesting Explanation of async/await in JavaScript Front-end Architecture: Stable and Volatile Dependencies Is it Safe to Compare JavaScript Strings? How to Access Object's Keys, Values, and Entries in JavaScript What Actually is a String in JavaScript? 3 Ways to Shallow Clone Objects in JavaScript (w/ bonuses) Checking if an Array Contains a Value in JavaScript JavaScript Event Delegation: A Beginner's Guide How to Parse URL in JavaScript: hostname, pathname, query, hash 3 Ways to Detect an Array in JavaScript How to Get the Screen, Window, and Web Page Sizes in JavaScript 3 Ways to Check If an Object Has a Property/Key in JavaScript How to Compare Objects in JavaScript Object.is() vs Strict Equality Operator in JavaScript Own and Inherited Properties in JavaScript 5 Differences Between Arrow and Regular Functions How to Use Object Destructuring in JavaScript Your Guide to React.useCallback()
A Simple Explanation of Hoisting in JavaScript
Dmitri Pavlutin · 2016-05-30 · via Dmitri Pavlutin Blog

Variables in a program are everywhere. They are small pieces of data and logic that interact with each other: and this activity makes the application alive.

In JavaScript, an important aspect of working with variables is hoisting, which defines when a variable is accessible. If you're looking for a detailed description of this aspect, then you're in the right place. Let's begin.

Table of Contents

  • 1. Introduction
  • 2. Function scope variables: var
  • 3. Block scope variables: let
    • Hoisting and let
  • 4. Constants: const
    • Hoisting and const
  • 5. Function declarations
    • Hoisting and function declaration
  • 6. Class declarations
    • Hoisting and class
  • 7. Final thoughts

1. Introduction

Hoisting is the mechanism of moving the variables and functions declaration to the top of the function scope (or global scope if outside any function).

Hoisting influences the variable life cycle, which consists of 3 steps:

  • Declaration - create a new variable. E.g. let myValue
  • Initialization - initialize the variable with a value. E.g. myValue = 150
  • Usage - access and use the variable value. E.g. alert(myValue)

The process usually goes this way. First, a variable should be declared, then initialized with a value, and finally used. Let's see an example:


// Declare

let strNumber;

// Initialize

strNumber = '16';

// Use

console.log(parseInt(strNumber)); // => 16


Open the demo.

A function can be declared and later used (or invoked) in the application. The initialization is omitted. For instance:


// Declare

function sum(a, b) {

return a + b;

}

// Use

console.log(sum(5, 6)); // => 11


Open the demo.

Everything looks simple and natural when steps are successive: declare -> initialize -> use. If possible, you should apply this pattern when coding in JavaScript.

JavaScript does not enforce following strictly this sequence and offers more flexibility. For instance, functions can be used before the declaration: use -> declare.

The following code sample first calls the function double(5), and only later declares it function double(num) {...}:


// Use

console.log(double(5)); // => 10

// Declare

function double(num) {

return num * 2;

}


Open the demo.

It happens because the function declaration in JavaScript is hoisted to the top of the scope.

Hoisting affects differently:

  • variable declarations: using var, let, or const keywords
  • function declarations: using function <name>() {...} syntax
  • class declarations: using class keyword

Let's examine these differences in more detail.

2. Function scope variables: var

The variable statement creates and initializes variables inside the function scope: var myVar, myVar2 = 'Init'. By default a declared yet not initialized variable has undefined value.

Plain and simple, developers use this statement from the first JavaScript versions:


// Declare num variable

var num;

console.log(num); // => undefined

// Declare and initialize str variable

var str = 'Hello World!';

console.log(str); // => 'Hello World!'


Open the demo.

Hoisting and var

Variables declared with var are hoisted to the top of the enclosing function scope. If the variable is accessed before the declaration, it evaluates to undefined.

Suppose myVariable is accessed before declaration with var. In this situation the declaration is moved to the top of double() function scope and the variable is assigned with undefined:


function double(num) {

console.log(myVariable); // => undefined

var myVariable;

return num * 2;

}

console.log(double(3)); // => 6


Open the demo.

JavaScript moves the declaration var myVariable to the top of double() scope and interprets the code this way:


function double(num) {

var myVariable; // moved to the top

console.log(myVariable); // => undefined

return num * 2;

}

console.log(double(3)); // => 6


Open the demo.

The var syntax allows not only to declare but right away to assign an initial value: var str = 'initial value'. When the variable is hoisted, the declaration is moved to the top, but the initial value assignment remains in place:


function sum(a, b) {

console.log(myString); // => undefined

var myString = 'Hello World';

console.log(myString); // => 'Hello World'

return a + b;

}

console.log(sum(16, 10)); // => 26


Open the demo.

var myString is hoisted to the top of the scope, however the initial value assignment myString = 'Hello World' is not affected. The above code is equivalent to the following:


function sum(a, b) {

var myString; // moved to the top

console.log(myString); // => undefined

myString = 'Hello World'; // remains

console.log(myString); // => 'Hello World'

return a + b;

}

console.log(sum(16, 10)); // => 26


Open the demo.

3. Block scope variables: let

The let statement creates and initializes variables inside the block scope: let myVar, myVar2 = 'Init'. By default a declared yet not initialized variable has undefined value.

let is scoped on a block statement (and function) level:


if (true) {

// Declare name block variable

let month;

console.log(month); // => undefined

// Declare and initialize year block variable

let year = 1994;

console.log(year); // => 1994

}

// name and year or not accessible here, outside the block

console.log(year); // ReferenceError: year is not defined


Open the demo.

Hoisting and let

let variables are registered at the top of the block. But when the variable is accessed before the declaration, JavaScript throws an error: ReferenceError: <variable> is not defined.

From the declaration statement up to the beginning of the block the variable is in a temporal dead zone and cannot be accessed.

Let's follow an example:


function isTruthy(value) {

if (value) {

/**

* temporal dead zone for myVariable

*/

// Throws ReferenceError: myVariable is not defined

console.log(myVariable);

let myVariable = 'Value 2';

// end of temporary dead zone for myVariable

console.log(myVariable); // => 'Value 2'

return true;

}

return false;

}

isTruthy(1)


Open the demo.

myVariable is in a temporal dead zone from the top of the block if (value) {...} until let myVariable. If trying to access the variable in this zone, JavaScript throws a ReferenceError.

4. Constants: const

The constant statement creates and initializes constants inside the block scope: const MY_CONST = 'Value', MY_CONST2 = 'Value 2'. Take a look at this sample:


const COLOR = 'red';

console.log(COLOR); // => 'red'

const ONE = 1, HALF = 0.5;

console.log(ONE); // => 1

console.log(HALF); // => 0.5


Open the demo.

When a constant is defined, it must be initialized with a value in the same const statement. After declaration and initialization, the value of a constant cannot be modified:


const PI = 3.14;

console.log(PI); // => 3.14

PI = 2.14; // TypeError: Assignment to constant variable


Open the demo.

Hoisting and const

Constants const are registered at the top of the block.

The constants cannot be accessed before declaration because of the temporal dead zone. When accessed before the declaration, JavaScript throws an error: ReferenceError: <constant> is not defined.

const hoisting has the same behavior as the variables declared with let statement (see hoisting and let).

Let's define a constant in a function double():


function double(number) {

// temporal dead zone for TWO constant

console.log(TWO); // ReferenceError: TWO is not defined

const TWO = 2;

// end of temporal dead zone

return number * TWO;

}

double(5);


Open the demo.

If TWO is used before the declaration, JavaScript throws an error ReferenceError: TWO is not defined. So the constants should be first declared and initialized, and later accessed.

5. Function declarations

The function declaration defines a function with the provided name and parameters.
An example of a function declaration:


function isOdd(number) {

return number % 2 === 1;

}

console.log(isOdd(5)); // => true


Open the demo.

The code function isOdd(number) {...} is a declaration that defines a function. isOdd() verifies if a number is odd.

Hoisting and function declaration

Hoisting in a function declaration allows using of the function anywhere in the enclosing scope, even before the declaration. In other words, the function can be called from any place of the current or inner scopes.

The following code from the start invokes a function, but defines it afterward:


// Call the hoisted function

console.log(equal(1, '1')); // => false

// Function declaration

function equal(value1, value2) {

return value1 === value2;

}


Open the demo.

The code works nicely because equal() is created by a function declaration and hoisted to the top of the scope.

Notice the difference between a function declaration function <name>() {...} and a function expression var <name> = function() {...}. Both are used to create functions, however, have different hoisting mechanisms.

The following sample demonstrates the distinction:


// Call the hoisted function

console.log(addition(4, 7)); // => 11

// The variable is hoisted, but is undefined

console.log(minus(10, 7)); // TypeError: minus is not a function

// Function declaration

function addition(num1, num2) {

return num1 + num2;

}

// Function expression

var minus = function (num1, num2) {

return num1 - num2;

};


Open the demo.

addition is hoisted entirely and can be called before the declaration.

However minus is declared using a variable statement and is hoisted too, but has an undefined value when invoked. This scenario throws an error: TypeError: minus is not a function.

6. Class declarations

The class declaration defines a constructor function with the provided name and methods. Classes are a great addition introduced by ECMAScript 6. Classes are built on top of the JavaScript prototypal inheritance and have some additional goodies like super (to access the parent class), static (to define static methods), extends (to define a child class), and more.

Take a look at how to declare a class and instantiate an object:


class Point {

constructor(x, y) {

this.x = x;

this.y = y;

}

move(dX, dY) {

this.x += dX;

this.y += dY;

}

}

// Create an instance

const origin = new Point(0, 0);

// Call a method

origin.move(50, 100);


Hoisting and class

The classes are registered at the beginning of the block scope. But if you try to access the class before the definition, JavaScript throws ReferenceError: <name> is not defined. So the correct approach is first to declare the class and later use it to instantiate objects.

Hoisting in class declarations is similar to variables declared with let statement (see 3.).

Let's see what happens if a class is instantiated before declaration:


// Use the Company class

// Throws ReferenceError: Company is not defined

const apple = new Company('Apple');

// Class declaration

class Company {

constructor(name) {

this.name = name;

}

}

// Use correctly the Company class after declaration

const microsoft = new Company('Microsoft');


Open the demo.

As expected, executing new Company('Apple') before the class definition throws ReferenceError. This is nice because JavaScript suggests using a good approach to first declare something and then make use of it.

7. Final thoughts

Hoisting in JavaScript has many forms. Even if you know exactly how it works, the general advice is to code variables in a sequence of declare > initialize > use. This will save you from unexpected variable appearances, undefined and ReferenceError.

As an exception, sometimes functions can be invoked before the definition: an effect of function declaration hoisting. It's useful in cases when you need to read quickly how functions are invoked at the top of the source file, without scrolling down and reading the details about function implementation.