English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

In-depth understanding of scope and variable hoisting in JS

Scope (Scoping)

For beginners in JavaScript, one of the most confusing points is scope; in fact, it's not just beginners. I have seen some experienced JavaScript programmers, but their understanding of scope is not deep. The reason why JavaScript scope is confusing is because its program syntax is similar to the C family of languages. My understanding of scope is that it will only have an effect on a certain range and will not affect the outside, being a closed space. In such spaces, external cannot access internal variables, but internal can access external variables.

C language variables are divided into global variables and local variables. The scope of global variables is any file and function access (of course, for other C files that are not variable definitions, the extern keyword needs to be used for declaration, and the static keyword can also limit the scope to the current file), while the scope of local variables is the block-level range covered by the nearest curly braces. Java has no global variables, but has class variables, member variables, and local variables, with different scopes depending on the access permissions such as public, protected, and private. I will not elaborate on this.

What are the scopes of JavaScript?

In ES5In, JavaScript has only two types of scopes: global scope and function scope.

The global scope is actually the scope of the global object, accessible from anywhere (unless covered by the function scope).

The scope of the function object is different from the local variable scope of C, its scope is the entire function range, regardless of where it is declared! This is what is called hoisting, that is, the concept of variable promotion. But don't worry, we will explain hoisting specifically later.

However, in ES6In, a new block scope (the range covered by the nearest curly braces) was added, but it is limited to variables declared with let.
Scope demonstration:

When defining a variable, if you do not write var, such as i=0, it will be defined as a global variable, with the scope of the global scope, otherwise it will be a local variable, with the scope of the function scope. The reason why var i=0 is said to be a global variable is that it has been declared in the global area, not within the function range, so it is the same as i=0.

As to why the result is like this, continue reading to find out.

Declaration form

Variable declaration:

Function declaration:

Variable promotion (Hoisting)

Brings up a question

What will the following code output?

I have interviewed many people for this question, and most people say that the output is the date. But the real result is undefined. Why is that? This brings up a concept--Hoisting, the Chinese meaning is variable promotion. The explanation of variable hoisting on MDN is as follows:

var hoisting

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.

This sentence translated is:}}

Because variable declarations are processed before any code execution, declaring variables anywhere in the code area is the same as declaring them at the beginning (at the top). That is to say, it looks like a variable can be used before it is declared! This behavior is what is called 'hoisting', that is, the declaration of variables is automatically moved to the top of the function or global code.

Note:Only declarations are hoisted, and definitions are not.

So, the above code is actually in the form of:

So, it should be understood that when console outputs, the tmp variable is only declared but not defined, so the output should be undefined.

It should be noted that although all declarations (including ES5of var, function, and ES6of function *will be hoisted, but var, function, and function *The hoisting of let, const, and class is different! The specific reasons can be seenThis explanation(This roughly means that although let, const, and class are also hoisted, they are not initialized. When they are accessed at this time, a ReferenceError exception will be reported. They need to be initialized when the statement is executed, and the state before initialization is called temporal dead zone). Let's see a piece of code to understand this:


a is hoisted here, but because it is defined later, the output is undefined

Although a is hoisted here, it reported a reference error!

The reason why it is like this

For this reason, it is recommended to write all the variables used at the top of the scope (global scope or function scope) when declaring variables, so that the code will look clearer and it will be easier to see which variable comes from the function scope and which comes from the scope chain (this article will not elaborate on this, please refer to Baidu for more information, and will be supplemented later if there is an opportunity).

Duplicate declaration

The output above is actually:1 2 2Although it looks like x is declared twice inside, as mentioned before, JavaScript's var variables have only two scopes: global scope and function scope, and declarations are hoisted. Therefore, x is actually declared only once at the top, var x=2The declaration will be ignored and is only used for assignment. That is to say, the code above is actually consistent with the one below.

The problem of promoting functions and variables simultaneously

What will happen if a function and a variable type are declared and defined at the same time? See the following code


A

The actual output is: function foo(){} which is the function content.

And if it is in this form


B

But its output becomes: undefined

Why is it like this?

Originally, function promotion is divided into two cases:

      One: function declaration. It is A above, function foo(){}

     Another one: function expression. It is actually B above, var foo=function(){}

The second form is actually the declaration and definition of var variables, so the output of B should be undefined, which can be understood.

And the first form of function declaration, when promoted, will be promoted as a whole, including the part of the function definition! Therefore, A and the following method are equivalent!

The reason is that:1The function declaration is promoted to the top;2The declaration is only performed once, so the declaration var foo='i am text' will be ignored later.

And since the priority of function declaration is higher than variable declaration, the following form is also the function content:

Summary

To thoroughly understand the scope and Hoisting of JS, just remember the following three points:

      1All declarations will be promoted to the top of the scope.

      2The same variable declaration is only performed once, and therefore other declarations will be ignored.

      3The priority of function declaration is higher than variable declaration, and function declaration will be promoted along with the definition.

Note:

Through the with statement, you can temporarily change the scope chain of the runtime context. At this time, when accessing variables not defined with var, it will first access the properties of the object in with, and then check the property along the scope chain upwards.

That's all for this article. I hope the content of this article can be helpful to everyone's learning or work. If you have any questions, you can leave a message for communication.

You May Also Like