Explaining JavaScript variable hoisting in detail

http://www.zcfy.cc/article/465Home

Login/Register
Home
In Translation
Q&A
Rank
Archive
loveky explains
JavaScript variable enhancement
loveky · 2016-06-12 Translation · 374 Read the original link
Variables can be seen everywhere in the program. They are data and logic that are always influencing and interacting with each other. It's these interactions that make the app come to life.

An important aspect of using variables in JavaScript is variable hoisting - it determines when a variable can be used by your code. If you're looking for a detailed introduction to this, you've come to the right place. Let's take a look.

1. Introduction
Hoisting is a mechanism for moving variable and function declarations to the very top of the function scope (or the global scope if not inside any function).

Hoisting affects the life cycle of a variable, the life cycle of a variable consists of 3 phases:

declaration - creating a new variable, e.g. var myValue
initialization - initializing the variable with a value e.g. myValue = 150
using - using the variable's value e.g. alert(myValue)
This process is usually performed like this: first declare a variable, then initialize it with a value, and finally use it. Let's see an example:

View on JS Bin

// declare
var strNumber;
// initialize
strNumber = '16';
// Use
parseInt(strNumber); // => 16
A function in a program can be declared first and used later. Initialization is ignored. For example:

View on JS Bin

// declare
function sum(a, b) {
  return a + b;
}
// use
sum(5, 6); // => 11
When these three steps are executed sequentially, Everything looks simple and natural. If you can, you should follow this pattern when programming in JavaScript.

JavaScript does not strictly follow this order, thus providing more flexibility. For example, the use of the function can be before the declaration. The example below calls the function double(5) before declaring the function function double(num) {...}:

see on JS Bin

// use
double(5); // => 10
// declare
function double(num) {
  return num * 2;
}
This is because function declarations in JavaScript are hoisted to the top of the scope.

Variable hoisting affects different aspects:

variable declaration: using the var, let or const keyword
Function declaration: using the function () {...} syntax
Class declaration: using the class keyword
Let's look at these differences in detail.

2. Function scope variables: var
variable declarations create and initialize a variable within function scope, for example var myVar, myVar2 = 'Init'. By default, declared but uninitialized variables have the value undefined.

Developers have been declaring variables this way since the first version of JavaScript.

View on JS Bin

// declare variable num
var num;
console.log(num); // => undefined
// declare and initialize variable str
var str = 'Hello World!';
console.log(str); // => 'Hello World!'
Hoisting and var

Variables declared with var are hoisted to the top of the function's scope. If the variable is accessed before its declaration, its value will be undefined.

Assume that myVariable is accessed before being declared by var. In this case, the declaration is moved to the top of the double() function and the variable is assigned the value undefined: see function double(num) {   console.log(myVariable); // => undefined   var

on JS Bin myVariable;




  return num * 2;
}
double(3); // => 6
JavaScript moves var myVariable to the top of double() when executing the code, like this: see function double(num) {

on JS Bin   var myVariable; // is moved to the top   console.log(myVariable); // => undefined   return num * 2; } double(3); // => 6 var syntax not only declares variables, but also declares them at the same time Assign an initial value to a variable: var str = 'initial value'. When a variable is hoisted, the declaration is moved to the top of the scope, but the assignment of the initial value is left in place: see function sum(a, b) {   console.log(myString); // => on JS Bin undefined   var myString = 'Hello World';   console.log(myString); // => 'Hello World'   return a + b; } sum(16, 10); // => 26


















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

View

function sum(a, b) {
  var myString; // Raise to top
  console.log(myString); // => undefined
  myString = 'Hello World'; // assignments are not affected
  console.log(myString); // => 'Hello World'
  return a + b;
}
sum(16, 10); // => 26
3. Block-scoped variables: let
let statement Create and initialize a variable at block scope: let myVar, myVar2 = 'Init'. By default, declared but uninitialized variables have the value undefined.

let is a huge improvement introduced in ECMAScript 6 that allows code to remain modular and encapsulated at the code block level: see if (true) {   // declare block level variable   let month;   console.log(month

on JS Bin ); // => undefined    // declares and initializes block-level variables






  let year = 1994;
  console.log(year); // => 1994
}
// month and year variables cannot be accessed outside the block
console.log(year); // ReferenceError: year is not defined
Boost vs. let

use let Defined variables are hoisted to the top of the code block. But if the variable is accessed before the declaration, JavaScript will throw the exception ReferenceError: is not defined.

In the declaration statement all the way to the top of the code base, the variable seems to be in a temporary dead zone and cannot be accessed.

Let's look at the following example:

View on JS Bin

function isTruthy(value) {
  var myVariable = 'Value 1';
  if (value) {
    /**
     * temporary dead interval for myVariable
     */
    // Throws ReferenceError: myVariable is not defined
    console.log(myVariable);
    let myVariable = 'Value 2';
    // the temporary dead interval of myVariable ends here
    console.log(myVariable); // => 'Value 2'
    return true;
  }
  return false;
}
isTruthy(1); // => true
from the let myVariable line up to the if (valaue) {.. .} are all temporary dead intervals for the myVariable variable. If the variable is accessed within this range, JavaScript will throw a ReferenceError exception.

An interesting question arises: is myVariable really hoisted to the top of the code block? Or is it undefined within the temporary death interval? JavaScript also throws ReferenceError when a variable is not defined.

If you look at the beginning of the function, var myVariable = 'Value 1' defines a variable named myVariable in the entire function scope. Inside the if (value) {...} block, if the variable defined by let is not hoisted, the value of myVariable in the temporary dead interval will be 'Value1'. From this we can confirm that the block-level variable is indeed hoisted.

The hoisting of let inside the block scope protects the variable from the outer scope. Throwing an exception when accessing a let-defined variable in a temporary dead interval encourages developers to follow better coding practices: declare first, use later.

These two limitations are an effective way to motivate writing better JavaScript in terms of encapsulation and code flow. This is the result of a lesson based on var usage - allowing access to variables before they are declared can be easily misunderstood.

4. Constant: const
A constant declaration creates and initializes a constant at block scope: const MY_CONST = 'Value', MY_CONST2 = 'Value 2'. Take a look at the example below:

View on JS Bin

const COLOR = 'red';
console.log(COLOR); // => 'red'
const ONE = 1, HALF = 0.5;
console.log(ONE); // => 1
console.log(HALF); // => 0.5
When declaring a variable, the variable must be initialized in the same statement. After declaration and initialization, the value of the variable cannot be modified.

See on JS Bin

const PI = 3.14;
console.log(PI); // => 3.14
PI = 2.14; // TypeError: Assignment to constant variable
hoisting and const

Constants defined with const are hoisted to the top of the code block .

Constants cannot be accessed until declared due to the temporary dead interval. If the constant is accessed before the declaration, JavaScript will throw an exception: ReferenceError: is not defined.

The hoisting effect of const-declared constants is the same as the hoisting of variables declared with let.

Let's declare a constant inside the double() function:

see on JS Bin

function double(number) {
   // Temporary dead interval of constant TWO
   console.log(TWO); // ReferenceError: TWO is not defined
   const TWO = 2;
   // Temporary dead interval of constant TWO ends here
   return number * TWO;
}
double(5); // => 10
JavaScript throws an exception due to using a constant before declaration. So when using constants, you should always declare, initialize, and then use.

5. Function declaration A
function declaration creates a function with the provided name and parameters.

An example of a function declaration:

look at JS Bin

function isOdd(number) {
   return number % 2 === 1;
}
isOdd(5); // => true
function isOdd(number) {...} is a definition function declaration. isOdd() is used to verify whether a number is odd.

Hoisting and

function allows you to use the function anywhere in the owning scope, even before the declaration. In other words, functions can be accessed from anywhere in the current scope or subscopes (no undefined values, no temporary dead ranges, no exceptions thrown).

The behavior of this boost is very flexible. Whether you use it first, declare it later, or declare it first and use it later, you can do what you want.

The example below calls a function at the beginning, and then defines it:

View on JS Bin

// call the hoisted function
equal(1, '1'); // => false
// function declaration
function equal( value1, value2) {
   return value1 === value2;
}
This code works because equal() is hoisted to the top of the scope.

Note the difference between function declaration function() {...} and function expression var = function() {...}. Both are used to create functions, but have different hoisting mechanisms.

The following example demonstrates the difference:

View on JS Bin

// call the hoisted function
addition(4, 7); // => 11
// the variable is hoisted, but the value is undefined
substraction(10, 7); // TypeError: substraction is not a function
// function declaration
function addition(num1, num2) {
   return num1 + num2;
}
// function expression
var substraction = function (num1, num2) {
  return num1 - num2;
};
addition is fully hoisted and can be called before declaration.

Substraction, however, is declared using the variable declaration statement, and although it is also hoisted, the value is undefined when called. So the exception TypeError: substraction is not a function will be thrown.

6. Class declaration The
class declaration creates a constructor with the provided name and parameters. Classes are a huge improvement introduced in ECMAScript 6.

Classes are built on top of JavaScript's prototypal inheritance and provide additional functionality such as super (access parent class), static (define static methods), extends (define subclasses).

Let's see together how to declare a class and create an instance:

see on JS Bin

class Point {
   constructor(x, y) {
     this.x = x;
     this.y = y;
   }
   move(dX, dY) {
     this.x += dX;
     this.y += dY;
   }
}
// create instance
var origin = new Point(0, 0);
// Call the instance's method
origin.move(50, 100);
hoisting and class

declarations will be hoisted to the top of the block scope. But if you use the class before the declaration, JavaScript will throw the exception ReferenceError: is not defined. So the correct way is to declare the class first and then use it to create instances.

The hoisting of a class declaration is similar to the hoisting of a let-defined variable.

Let's see what happens when we create a class instance before declaration:

View on JS Bin

// using Company class
// throws ReferenceError: Company is not defined
var apple = new Company('Apple');
// class declaration
class Company {
  constructor(name) {
    this.name = name;
  }
}
// use Company class after declaration
var microsoft = new Company('Microsoft');
as expected, execute new Company('Apple') before class definition A ReferenceError exception will be thrown. This is nice because JavaScript encourages a declare-before-use approach.

Classes can also be created using class expressions using variable declaration statements (var, let, and const). Let's look at the following scenario:

View on JS Bin

// use Sqaure class
console.log(typeof Square); // => 'undefined'
//Throws TypeError: Square is not a constructor
var mySquare = new Square(10);
// use variable declaration statement declare class
var Square = class {
  constructor(sideLength) {
    this.sideLength = sideLength;
  }
  getArea() {
    return Math.pow(this.sideLength, 2);
  }
};
// use Square class after declaration
var otherSquare = new Square(5);
This class is defined using the variable declaration statement var Square = class {...}. The Square variable is hoisted to the top of the scope, but its value is undefined until this line of code that declares the variable. So the var mySquare = new Square(10) statement is equivalent to using undefined as a constructor, which causes JavaScript to throw a TypeError: Square is not a constructor exception.

7. Final Thoughts
As explained in this article, hoisting in JavaScript comes in many forms. Even if you know how it works, it is generally recommended to use variables in the order of declaration > initialization > use. ECMAScript 6 strongly supports this usage through let, const, and class hoisting. This will save you from encountering unexpected variables, undefined and ReferenceError.

There is an exception where a function can execute before it is defined. This is when the developer needs to quickly understand how the function is called, because then there is no need to scroll to the bottom to read the specific implementation of the function.

For example, this article explains how this approach increases the readability of Angular controllers code.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327064407&siteId=291194637