JS scope and scope chain details

  • 2020-05-27 04:14:37
  • OfStack

(1) scope

The scope of a variable (scope) is the area of that variable defined in the program source code.

1. Lexical scope is used in JS (lexical scope)

Variables that are not declared in any function (those that omit var are also global) are called global variables (global scope)

Variables declared in a function have a function scope (function scope) and are local variables

Local variables have a higher priority than global variables


var name="one";
function test(){
  var name="two";
  console.log(name); //two
}
test();

Omitting var from a function affects the global variable because it has actually been overwritten as a global variable


var name="one";
function test(){
  name="two";
}
test();
console.log(name); //two

Function scope, which means that a function is the basic unit of a scope, js does not have block-level scope like c/c++, if for, etc


function test(){
  for(var i=0;i<10;i++){
    if(i==5){
      var name = "one";
    }
  }
  console.log(name); //one
}
test();  // Because it's a function level scope, it's accessible name="one"

And, of course, js also USES higher-order functions, which you can think of as nested functions


function test1(){
  var name = "one";
  return function (){
    console.log(name);
  }
}
test1()();

test1() will then call the outer function, return an inner function, continue (), the corresponding call to perform the inner function, so the output "one"

Nested functions involve closures, which we'll talk about later. Here the inner function can access the variable name declared in the outer function, which involves the scope chain mechanism

2. Advance statement in JS

The function scope in js means that all variables declared in a function are always visible in the body of the function. Also, variables can be used before they are declared, which is called declaration lead (hoisting)

tip: advance declaration occurs when the js engine is precompiled. It occurs before the code is executed

Such as


var name="one";
function test(){
  console.log(name);  //undefined
  var name="two";
  console.log(name); //two
}
test();

The top is the bottom


var name="one";
function test(){
  var name;
  console.log(name);  //undefined
  name="two";
  console.log(name); //two
}
test();

Let's try var, right? This is the name in the function that has become a global variable, so it's no longer undefined


var name="one";
function test(){
  console.log(name);  //one
  name="two";
  console.log(name); //two
}
test();

3. It is worth noting that none of the above mentioned parameters are passed. What if test has parameters?


function test(name){
  console.log(name);  //one
  name="two";
  console.log(name); //two
}
var name = "one";
test(name);
console.log(name); // one

As I said before, the base type is passed by value, so name passed into test is actually just one copy, which is cleared when the function returns.
Don't think that name="two" in the function has changed global name, because they are two separate name

(2) scope chain

The advanced functions mentioned above involve a chain of scopes


function test1(){
  var name = "one";
  return function (){
    console.log(name);
  }
}
test1()();

1. Introduce a long paragraph to explain:
Each piece of js code (global code or function) has a scope chain associated with it (scope chain).

The scope chain is a list or linked list of objects that define the "scope" variables in the code.

When js need to find the value of the variable x (a process called variable resolution (variable resolution)), it can be started from the chain of the first object lookup, if this object has a property called x, can directly use the value of this attribute, if the first object without attributes, called x js under one of the chain will continue to find the object. If the second object still does not have a property named x, it continues to look for the next one, and so on. If no object on the scope chain contains the property x, x is considered not to exist on the scope chain of this code, and a reference error (ReferenceError) exception is thrown.

2. Example of scope chain:

In js's topmost code (that is, code that does not include any function definitions), the scope chain consists of one global object.

In a non-nested function body, there are two objects in the scope chain, the first being the object that defines the function parameters and local variables, and the second being the global object.

Within a nested function, there are at least three objects in scope.

3. Scope chain creation rules:

When a function is defined (note that it starts when defined), it actually holds a chain of scopes.

When this function is called, it creates a new object to store its arguments or local variables, adds the object to that scope chain, and creates a new, longer "chain" that represents the scope of the function call.

For nested functions, the situation is different: each time an external function is called, the internal function is redefined once more. Because every time an external function is called, the scope chain is different. Internal functions are subtly different every time they are defined - the internal function code is the same every time the external function is called, and the chain of scopes associated with this code is different.

(tip: understand the three points above and remember them. You'd better say them in your own words, or memorize them, because the interviewer will ask you directly: please describe 1 scope chain...)

A practical example of a scope chain:


var name="one";
function test(){
  var name="two";
  function test1(){
    var name="three";
    console.log(name);  //three
  }
  function test2(){
    console.log(name);  // two
  }
  test1();
  test2();
}
test();

The top is a nested function, corresponding to which there should be three objects in the scope chain
So when you call it, you need to look up the value of name, and you look it up in the scope chain

When test1() is successfully called, the order is test1()- > test()- > The global object window completes the search and returns because the value three of name was found on test1()

When test1() is successfully called, the order is test2()- > test()- > The global object window cannot find the value name on test2(), so it looks for the value name in test(), finds the value two, and returns the search

Here's another example: sometimes we make mistakes, and we are often cheated in interviews.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
function buttonInit(){
    for(var i=1;i<4;i++){
        var b=document.getElementById("button"+i);
        b.addEventListener("click",function(){
            alert("Button"+i); // Are all Button4
        },false);
    }
}
window.onload=buttonInit;
</script>
</head>
<body>
<button id="button1">Button1</button>
<button id="button2">Button2</button>
<button id="button3">Button3</button>
</body>
</html>

Why is that?
According to the rules for finding variables in the scope chain:


b.addEventListener("click",function(){
            alert("Button"+i);
        },false);

So here's a function, it's an anonymous function, and since it's a function, it has an object in the scope chain, and this function USES the variable i in it, and it naturally looks for it in the scope.
The search order is this anonymous function -- > The external function buttonInit() -- > Global object window

I couldn't find i in the anonymous function, so I went to buttonInit(), ok, and I found it in for,

When the registration event is over, don't assume that it will drop i one by one, because variables within the scope of the function are directly visible to the scope of 1, which means that they will remain in the final state

When the anonymous function wants to use i, the registration event is finished, i has become 4, so it is Button4

So what's the solution?

Pass it in, and each time you loop, you use an anonymous function, and you pass in i from for, and the rules of the anonymous function are the code


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
function buttonInit(){
    for(var i=1;i<4;i++){
        (function(data_i){
        var b=document.getElementById("button"+data_i);
        b.addEventListener("click",function(){
            alert("Button"+data_i);
        },false);
        })(i);
    }
}
window.onload=buttonInit;
</script>
</head>
<body>
<button id="button1">Button1</button>
<button id="button2">Button2</button>
<button id="button3">Button3</button>
</body>
</html>

So you can Button1.. 2.. 3 the

4. The above is the basic description of the scope chain. In addition, the with statement can be used to temporarily extend the scope chain (with is not recommended).

The grammatical form is as follows:

with(object)

statement

This with statement, adds object to the head of the scope chain, then executes statement, and finally restores the scope chain to its original state

Simple usage:

For example, assign value to the value of each item in the form

We can just go like this


var f = document.forms[0];
f.name.value = "";
f.age.value = "";
f.email.value = "";

After the introduction of with (since using with will cause series 1 problems, please use the above form)


with(document.forms[0]){
f.name.value = "";
f.age.value = "";
f.email.value = "";
}

In addition, if an object o has the x property, o.x = 1;
Then using


with(o){
  x = 2;
}

o.x = 2;
If o does not define the property x, its function is equivalent to x = 2; One global variable.

Because with provides a shortcut to read o's properties, it cannot create properties that o itself does not have.

The above is the whole content of this article, I hope to be able to help you learn javascript.


Related articles: