The introduction
In JavaScript, there are scopes, scope chains, and closures. We may start out thinking we know what these are (and I did when I was just getting started), but as we dig deeper, we realize that we only scratch the surface. So, this article will go into more detail about scopes, scope chains, and closures.
Let’s use a problem to understand the formation process of scope, scope chain and closure
let x = 1;
function A(y){
let x = 2;
function B(z){
console.log(x+y+z);
}
return B;
}
let C = A(2);
C(3);
Copy the code
For the above solution diagram, there are the following explanations:
-
When a function is created, a heap is created and the current function Scope is initialized. The Scope ([[Scope]]) is the variable object VO/AO in its context.
-
When a function is executed, a new execution context is created -> initialize this to -> initialize the ScopeChain ([[ScopeChain]]) -> create the AO variable object store variable
-
In the context of EC(A) execution, A closure is formed when the heap is occupied by the global variable C and cannot be destroyed out of the stack.
-
The red line in the diagram represents the scope chain. In a scope, the variables it needs are not in the current scope and will be looked up level by level.
This simple question introduces the concepts of scope, scope chain, and closure, which will be formally explained in this article.
First, scope
Scope ([[Scope]]) is the accessible Scope of variables and functions, that is, Scope controls the visibility and life cycle of variables and functions.
1.1 Lexical scope and dynamic scope
1.1.1 Lexical scope
Lexical scope is also static, and is used in JavaScript. Lexical scope is the scope of the definition at the lexical stage. In other words, the lexical scope is determined by where you write the variable and block scope when you write the code. So the lexical parser keeps its scope constant when it processes code (most of the time)
Here’s an example to help you understand:
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
bar();
Copy the code
If the above example uses lexical scope, it would be executed as follows:
The bar() function is executed first, and the foo() function is executed in the bar() function, which outputs the value of value. It first looks to see if there is a value in the current scope, and if there isn’t, it looks up one level, and finally prints 1
1.1.2 Dynamic scope
Dynamic scope is the opposite of lexical scope. Let’s use the above example:
Suppose the above example uses dynamic scope:
It still executes the function as if it were lexically scoped, except that when foo() is executed, it does not look up the value one level, but from the scope of the calling function, so the final output is 2.
1.2 Global scope
Objects that can be accessed anywhere in your code have a global scope. In general, there are three ways to have a global scope
1.2.1 Outermost functions and variables defined outside the outermost functions
var globalValue = `global value`;
function checkGlobal() {
var localValue = `local value`;
console.log(localValue); // "local value"
console.log(globalValue); // "global value"
}
console.log(globalValue); // "global value"
console.log(checkGlobal); // "global value"
console.log(localValue); // "Uncaught ReferenceError: localValue is not defined"
Copy the code
In the example above, globalValue is a global variable that can be accessed anywhere, while localValue is a local variable that can only be accessed inside a function
1.2.2 All variables not directly assigned by definition
function checkGlobal() {
var localValue = 'local value';
globalValue = 'global value';
console.log(localValue, globalValue); // 'local value' 'globalValue'
}
console.log(globalValue); // 'globalValue'
console.log(localValue); // "Uncaught ReferenceError: localValue is not defined"
Copy the code
1.2.3 Properties of all Window objects
1.3 Function scope
A function scope is a variable declared inside a function, which is the opposite of a global scope. The inner scope can access the outer scope, but the outer scope cannot access the inner scope.
function check() {
var localValue = 'local value';
console.log(localValue); // 'local value'
}
console.log(localValue); // "Uncaught ReferenceError: localValue is not defined"
Copy the code
1.4 block-level scope
Block-level scopes can be declared by lets and const, and the declared variables specify that they are not accessible outside the block-level scope.
1.4.1 When block-level scopes are created
-
Inside a function
-
Inside a code block
1.4.2 Characteristics of block-level scope
- Declared variables are not promoted to the top of the code block
Variables declared by let or const are not promoted to the top of the current scope.
function check(bool) {
if(bool) {
let result = 1;
console.log(result);
}
console.log(result);
}
check(true); // 1 Uncaught ReferenceError: result is not defined
check(false); // Uncaught ReferenceError: result is not defined
Copy the code
If you want to access result, you need to manually promote the variable to the top of the current scope yourself. Like this,
function check(bool) {
let result = null;
if(bool){ result = 1 } console.log(result); }...Copy the code
- No duplicate declaration
Variables that have already been declared in the same level of scope cannot be declared again.
// 1true;
let bool = false; // Uncaught SyntaxError: Identifier 'bool'Has already been declared // Var bool =true;
function check() {
let bool = false; // no errors here //..... }Copy the code
- Use in loops
Variables declared in a for loop are used only inside the loop.
for(let i = 0; i < 1; i++) {
console.log(i); // 0
}
console.log(i); // Uncaught ReferenceError: i is not defined
Copy the code
But inside the loop is a separate scope
for(let i = 0; i < 2; i++) {
let i = 'hello';
console.log(i); // 'hello' 'hello'
}
Copy the code
Scope chain
2.1 Definition and formation of scope chain
When the desired variable cannot be found in its scope, it looks up layer by layer until it finds the global scope and gives up the search. This layer by layer relationship is the scope chain.
var a = 1;
function check() {
return function() { console.log(a); Log (b); // If a is not found in the current scope, a is found in the current scope. // Same thing, so output"Uncaught ReferenceError: b is not defined"} } var func = check(); // return the anonymous function func(); // Execute an anonymous functionCopy the code
Third, the closure
3.1 Definition of closures
Closures occur when a function can remember and access its lexical scope. Even if the function is executed outside the current lexical scope.
3.2 Formation of closures
Let’s look at a piece of code
function foo() {
var a = 1;
return function() {
console.log(a);
}
}
var bar = foo();
bar();
Copy the code
The result of the foo() function is returned to bar, which is not destroyed because the variable a is still in use, and then the bar() function is executed. In this way, we can access variables in the function’s inner scope from the outer scope. This is the closure.
Closure formation conditions:
-
Nested function
-
An inner function refers to a local variable of an outer function
3.3 The role of closures
-
You can read variables inside a function
-
The value of a variable can be kept in memory for a long time with a long life cycle.
-
Can be used to implement JS modules (JQuery libraries, etc.)
JS module is a JS file with specific functions, all the data and functions are encapsulated in a function inside (private), only to expose an object or function containing multiple methods to the outside, the user of the module, only through the object exposed by the module to call the method to achieve the corresponding function.
(function() {
var a = 1;
function test() {
return a;
}
window.module = {a, test}; // exposed})()Copy the code
<! DOCTYPE html> <html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<script src="./1.js"> </script>
<title>Document</title>
</head>
<body>
<script>
console.log(module.a); // 1
console.log(module.test()); // 1
</script>
</body>
</html>
Copy the code
3.4 Features of closures
-
Every function is a closure, and a function can remember the scope in which it was defined, and where the function goes, the scope goes when it was defined.
-
A memory leak
A memory leak is an object that exists when you don’t need it. So you can’t abuse closures. When we are done with the closure, we should set the reference variable to NULL.
function outer(){
var num = 0;
return function add(){ num++; console.log(num); }; } var func1 = outer(); func1(); // 1 func1(); Var func2 = outer(); var func2 = outer(); func2(); // 1 [rereference function when closure is new] func2(); / / 2Copy the code
3.5 Application of closures
Now we need to implement the output of the number of button clicks
Let’s write an HTML
<button>1</button>
<button>2</button>
Copy the code
To write JS
let buttons = document.getElementsByTagName('button');
for(var i = 0; i < buttons.length; i++) {
buttons[i].onclick = function() { console.log(i + 1); }}Copy the code
The first time we might write code like this, but we’ll see that there’s a problem with this code, that no matter how many buttons I click, it’ll print 3. This is because I is the global variable, and by the time the click event is executed, I has changed to 3
We can solve this problem in two ways
let
The statement
Change the var in the above code to let
- closure
for(var i = 0; i < buttons.length; i++) {
(function(k){
buttons[k].onclick = function() {
console.log(k + 1);
}
})(i)
}
Copy the code
The interview questions
let x = 5;
function fn(x) {
return function(y) { console.log(y + (++x)); }}let f = fn(6);
f(7);
console.log(x);
Copy the code
conclusion
This article is about scopes, scope chains, and closures. If you think it’s helpful, please give this article a thumb-up. If there’s anything wrong, please point it out
Finally, share my public number “Web front-end diary”, welcome to come to pay attention to ~