scoping and hoisting of variables in javscript

First look at an example:
var a = 1;
function foo() {
  if (!a) {
    var a = 10;
  }
   alert(a);
};
foo();

What is the result of the above code when it is run?

Beginner ideas:

1. The global variable a is created and its value is defined as 1
2. The function foo is created
3. In the function body of foo, the if statement will not be executed, because !a will convert the variable a into a boolean false value, which is false
4. Skip the conditional branch, alert variable a, the final result should be output 1, but the correct answer is 10.

Why 10? This is due to variable hoisting:

Declaration and Definition

To understand variable hoisting , let's first look at a simple case:

var a = 1;
the following example is called "declaring a variable":

var a;

The following example is called "defining a variable":

var a = 1;

Declaration: means that you claim the existence of something, such as a variable or a function; but you do not say what such a thing is, just tell the interpreter that such a thing exists;
Definition: means that you specify something The specific implementation, such as what is the value of a variable, what is the function body of a function, exactly expresses the meaning of such things.

in conclusion:

var a; // this is the declaration
a = 1; // this is the definition (assignment)
var a = 1; // two in one: declare the existence of the variable and assign to it

Here comes the point: when you think you only do one thing (var a = 1), the interpreter actually breaks it down into two steps, one is the declaration (var a) and the other is the definition (a = 1).

How does this relate to variable hoisting?

Going back to that confusing example at the beginning, I tell you how the interpreter analyzes your code:

var a;
a = 1;
function foo() {
  var a;    // 关键在这里
  if (!a) {
    a = 2;
  }
  alert(a);   // 此时的 a 并非函数体外的那个全局变量
}
As shown in the code, the interpreter declares a new variable a after entering the function body, and assigns the value 10 to the new variable a regardless of the condition of the if statement.

Scope:

One might ask: "Why not declare the variable a inside the if statement?"

Because JavaScript does not have block-level scope, only function scope (Function Scoping), so if you don't see a pair of curly braces {}, it means that a new scope is generated, which is different from C!

When the parser reads the if statement, it sees that there is a variable declaration and assignment, so the parser hoists its declaration to the top of the current scope (this is the default behavior and cannot be changed), this behavior is called Variable promotion.

What if I just want alert(a) to output that 1?

Create new scope

When alert(a) is executed, it will look for the location of the variable a. It starts from the current scope (or outwards) until it reaches the top-level scope. If it is not found, it will report undefined.

Because in the sibling scope of alert(a), we declare the local variable a again, so it reports 10; so we can move the declaration of the local variable a down (or inward), so that alert(a) just can't find it.

Remember: JavaScript only has function scope!

var a = 1;
 
function foo() {
  if (!a) {
    (function() {   // 这是上一篇说到过的 IIFE,它会创建一个新的函数作用域
      var a = 2;    // 并且该作用域在 foo() 的内部,所以 alert 访问不到
    }());        // 不过这个作用域可以访问上层作用域哦,这就叫:“闭包”
  };
  alert(a);
};
 
foo();
You may have read in countless JavaScript books and articles: "Always keep the declarations of all variables in scope at the top of the scope", because this will save you from the variable hoisting feature, which is in the current scope. Which variables are accessible. However, hoisting of variable declarations is not all there is to hoisting. In js, there are four ways to bring names into scope (by priority):

1. Language-defined naming: such as this or arguments, they are valid in all scopes and have the highest priority, so you cannot name variables like this anywhere, which is meaningless
2. Formal parameters: Formal parameters declared when a function is defined are hoisted into the function's scope as variables. So the formal parameters are local, not external or global. Of course, you can pass in external variables when executing the function, but after passing in, it is local
3. Function declaration: Functions can also be declared inside the function body, but they are also local
4. Variable declaration: This takes precedence The level is actually still the lowest, but they are also the most commonly used

Further understanding of the difference between declaration and definition: hoisting only promotes the name, not the definition

Difference between function declaration and function expression

Let's look at two examples:

function test() {
  foo();
 
  function foo() {
    alert("我是会出现的啦……");
  }
}
 
test();
 
 
function test() {
  foo();
 
  var foo = function() {
    alert("我不会出现的哦……");
  }
}
test();

In the first example, the function foo is a declaration, and since it is a declaration, it will be hoisted (I deliberately wrapped an outer scope, because the global scope requires your imagination, not so intuitive, but the principle is the same) , so the scope knows about the existence of function foo before foo() is executed. This is called a function declaration, and the function declaration is hoisted to the top of the scope along with the name and the function body.

In the second example, only the variable name foo is hoisted, and its definition remains in place. Therefore, before executing foo(), the scope only knows the name of foo, not what it is, so the execution will report an error (usually: undefined is not a function). This is called a function expression, and only the name of the function expression will be hoisted, the body of the defined function will not.

 

Guess you like

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