Scope and scope chain

1. Global scope

JS has a global object, window. Variables declared globally are properties of window. Properties not declared using declarators are also properties of Window.

var a = 10;
b = 10;
function fun(){
    c = 10;
    var d = 10;
}
fun();
console.log("window.a".window.a);   / / 10
console.log("window.b".window.b);   / / 10
console.log("window.c".window.c);   / / 10
console.log("window.d".window.d);   //undefined
Copy the code

2. Function scope

When we define a function, there will be an implicit property called scope by default, namely the field, which holds the information of the function definition. This property refers to an array containing a chain of function execution contexts. The first item in the array is the scope of the function itself.

If we want to access a property, we look for it in order in the field. So the following code can only print the value of b, because A was not defined at the time the function was defined.

var b = 2; 
function foo() { 
	console.log(b); 
	console.log(a); 
} 
(function () { 
	var a = 1; foo(); }) ();/ / 2
//error
Copy the code

3. Scope chain

A function has a property that points to a chained execution context, at the bottom of which is the function’s own scope, above which is the parent scope, and finally to the window scope.

When a function is defined, it directly has the scope of the parent module. For example, a function defined in Window directly has the scope of window.

At function execution time, if access to a property is not available in the current function, it is looked for in the chained execution context.

Let’s look at an example

var a=10
function fun1(){
	var b=20;
	function fun2(){
	    / /...
	}
	fun2();
}
fun1();
Copy the code

As shown above, precompilation and scope chains are used to interpret the specific steps of code execution

1.First, the global existence scope GO goes towindowall2.When fun1 is defined, it inheritswindowScope (fun1):GO -->2Scope (fun1):AO(fun1) --> GO --> Scope (fun1) --> GO -->3.Scope: AO(fun1) --> GO --> Scope (fun2): AO(fun1) --> GO --> fun2: AO(fun1) --> GO -->4.Scope (fun2): AO(fun2) --> AO(fun1) --> GO --> Scope (fun2): AO(fun2) --> AO(fun1) --> GO -->5After executing the function fun2, destroy its scope6After executing fun1, destroy its scopeCopy the code

Property access

If you want to access a variable in function B, the system will look for it in the scope of function B. Scope is an array, and it will access it from the 0th bit. The first bit is the scope of function B. If it cannot find it, it will continue to look for it, that is, the scope of function A.

If it can’t find any more, it continues down, looking in the window’s scope, and throwing an error if it can’t find any more.

var cc = 123;
function a(){
    function b(){
        var bb = 234;
        aa = 0;
        console.log(cc);
    }
    var aa = 123;
    var cc = 111;
    b();
    console.log(aa);       
}
a();
Copy the code

So the result of the function is zero

111
0
Copy the code

2. Closure

When an internal function is saved externally, a closure is generated. After the closure is generated, the inner function can still access the scope of the outer function in which it resides.

Principle 1.

When an inner function is defined, it creates a scope chain belonging to the scope property of the inner function, which directly inherits the scope chain of the parent function.

When it has access to the parent function’s variables, the scope chain is not destroyed when the parent function is destroyed, and the inner function can still access the parent function’s variables.

2. Ways to avoid closures

(1) Execute the function immediately


(function(){ 
    var a; 
    //code} ()); (function(){
    var a; 
    //code}) ();Copy the code

The disadvantage of parentheses, however, is that if the previous line of code does not include a semicolon, the parentheses will be interpreted as a function call from the last line of code, resulting in completely unexpected and difficult to debug behavior. Operators such as the plus sign have similar problems.

Another way to write it

void function () {
	var a = 100;
	console.log(a); } ();Copy the code

Semantically, void means to ignore the value of the following expression and change it to undefined

(2) Use const and let

3. Use of closures

Implement a counter using closures

function counterCreate(){
    var count = 0;
    return function(){
        count++;
        console.log(` count${count}Time `); }}var addCount = counterCreate();
addCount();// Count 1 time
addCount();// Count 2 times
addCount();// Count 3 times
addCount();// Count 4 times
Copy the code

The inner function uses the count attribute of the outer function, so after the outer function is destroyed, count can still be used by the inner function, but cannot be accessed by the external function.

4. Pros and cons of closures

Benefits of closures

  1. You want a variable to be stored in memory for a long time
  2. Avoid contamination of global variables
  3. Private members exist
  4. Used to cache

Disadvantages of closures

Prone to memory leaks

Use closures to define private variables for objects

var Person = (function () {
var privateData = {},
  privateId = 0;
function Person(name) {
  Object.defineProperty(this."_id", { value: privateId++ });
  privateData[this._id] = {
    name: name,
  };
}
Person.prototype.getName = function () {
  return privateData[this._id].name;
};
returnPerson; }) ();Copy the code

The last

Thank you for reading this post. If you find this post useful, please like it before you leave