First, scope
Scope is the life cycle of a variable.
- Global scope
- Function scope
- Block-level scope
- Lexical scope
- Dynamic scope
1. Global scope
Global variables: The life cycle will exist throughout the program. Can be accessed by any function or method in the program. It can be modified by default in javascript.
1.1 Display Statement
Declarations with the keyword var:
var a = 1;
var f = function(){
console.log("come on"); }; // The global variable will be attached to the window object console.log(window.a); console.log(window.f);Copy the code
1.2 Implicit declaration
function f(num){
result = num + 1;
return result;
}
f(1);
console.log(window.result);Copy the code
The variable result, without the var keyword, is also implicitly declared as a global variable. Mount to the Window object.
2. Function scope
function f(){
var a = 1;
}
console.log(a);Copy the code
2.1 How do I access variables in a function scope?
Method 1: Return the internal variables of a function
function f(num){
var result = num++;
return result;
}
console.log(f(1));Copy the code
function f(num){
var result = num + 1;
return result;
}
console.log(f(1));Copy the code
function f(num){
var result = ++num;
return result;
}
console.log(f(1));Copy the code
The above three programs also illustrate the difference between I ++ and ++ I.
Access variables inside functions through closures
function outer(){
var value = 'inner';
return function inner() {return value;
}
}
console.log(outer()());Copy the code
2.2 Execute the function immediately
Function () {}) () automatically executes the contents of the package, eliminating the effects of global variables.
(function(){
var a = 1;
var foo = function(){
console.log("haha");
}
})();
console.log(window.a);
console.log(window.foo);Copy the code
Block-level scope
Prior to ES6, there was no concept of block-level scope.
for(var i = 0; i < 3; i++){
}
console.log(i); Copy the code
Var (); var (); var ();
var i;
for(i = 0; i < 3; i++){
}
console.log(i); Copy the code
If you need block-level scoping, you can use the let keyword, which does not have variable promotion.
for(let i = 0; i < 3; i++){
}
console.log(i);
Copy the code
Also available for block-level scope is the const keyword.
if(true){
const a = 1;
}
console.log(a);Copy the code
The role of block-level scope and frequently asked interview questions
for(var i = 0; i < 3; i++){
setTimeout(function(){ console.log(i); }, 200); }Copy the code
Why is I 3?
I is in the global scope. For () loop is a synchronous function. SetTimeout is an asynchronous operation.
How do we make it output the way we want it to?
Method 1: Let is the easiest
for(let i = 0; i < 3; i++){
setTimeout(function(){ console.log(i); }, 200); }Copy the code
Method 2: call function, create function scope;
for(var i = 0; i < 3; i++){
f(i);
}
function f(i){
setTimeout(function(){ console.log(i); }, 200); }Copy the code
Method 3. Execute the function immediately
for(var i = 0; i < 3; i++){
(function(j){
setTimeout(function(){
console.log(j);
},200)
})(i);
}Copy the code
Execute the function and function call immediately, writing down I in the for loop, assigning I to j, and then printing 0,1,2.
Lexical scope
The scope of a function is determined when the function is defined.
var value = 'outer';
function foo(){
var value = 'middle';
console.log(value); //middle
function bar(){
var value = 'inner';
console.log(value); //innner
}
return bar();
}
foo();
console.log(value); //outerCopy the code
When we want to use declared variables: the JS engine always looks from the nearest field to the outer field;
Example: Interview questions
var a = 2;
function foo(){
console.log(a);
}
function bar(){
var a = 3;
foo();
}
bar();Copy the code
If it’s lexical scope, that’s the javascript environment today. The variable a is first looked up in foo(), and if it doesn’t find it, it looks up the code level above it based on where it was written. In this case, global scope, it finds and assigns a value of 2, so the console prints 2.
As we said, lexical scope is determined statically when code is written. The scope in Javascript is the lexical scope (in fact most languages are based on lexical scope), so this code runs in the browser with output 2.
Scope “masking”
The scoped lookup starts at the innermost scope of the runtime and works its way up and out until the first matching identifier is found. You can define identifiers of the same name in multiple nested scopes. This is called the “shadowing effect,” in which an internal identifier “overshadows” an external identifier.
var a = 0;
function test(){ var a = 1; console.log(a); / / 1}test(a);Copy the code
var a = 0;
function test(){ var a = 1; console.log(window.a); / / 0}test(a);Copy the code
This technique allows access to global variables that are masked by the same name. But non-global variables that are obscured cannot be accessed anyway.
Dynamic scope
Dynamic scopes don’t care how and where functions and scopes are declared, only that they start fromWhere to call.
Dynamic scoping, where scopes are based on the call stack rather than nested scopes in code;
Listen to the interview questions:
var x = 3;
var y = 3;
functionA(y){ var x = 2; var num = 3; num++; / / 4function B(num){
returnx * y * num; //x,y,num:1,5,4} x = 1;return B;
}
console.log(A(5)(4));
Copy the code
Resolution:
C) return B; c) return B; , so the value of x has been changed to 1 before the function is called; So return 20.
Scope chain
Each javaScript Function is represented as an object, or more specifically, an instance of the Function object.
Function objects, like other objects, have programmatically accessible properties. And a set of properties that cannot be accessed by code, which are internal properties provided to the JavaScript engine for access. One of these attributes is [[Scope]], defined by the ECMA-262 standard, third edition.
The inner attribute [[Scope]] contains the collection of objects in the Scope in which the function was created.
This set is called the function’s scope chain, and it determines which data can be accessed.
Source: High Performance JavaScript;
Ex. :
function add(x,y){
return x + y;
}
console.log(add.prototype);
Copy the code
The [[Scope]] property is an array that holds the chain of scopes.
Understand the principles of lexical scope
var a = 2;
function foo(){
console.log(a); //2
console.log(foo.prototype);
}
function bar(){
var a = 3;
console.log(a); //3
foo();
console.log(bar.prototype);
}
bar();Copy the code
Node environment:
Browser:
Confused: Why there are two objects in the scopes array in Node and only one object in the scopes array in the browser?
Reason: Node’s modularity essentially adds an anonymous function to the outer layer, because node’s modularity wraps an anonymous function around every JS file at compile time. So there will be two objects in the scopes. If you open the scopes[0], you’ll see that they do contain variables or functions that are global in the browser, whereas in the Node environment they are wrapped in a layer of anonymous functions that would be present in a closure.
var a = 2;
function bar(){
var a = 3;
console.log(a); //3
foo();
console.log(bar.prototype);
function foo(){
console.log(a); //3
console.log(foo.prototype);
}
}
bar();Copy the code
Node environment:
Browser:
The global scope chain is determined when the global execution context is initialized.
Proof:
console.log(add.prototype); / / 1 statement beforefunctionadd(x,y){ console.log(add.prototype); / / 2 runtimereturnx + y; } the add (1, 2); console.log(add.prototype); / / 3 after the executionCopy the code
One statement before
2 the runtime
After 3 to perform
The scope chain is determined in the context in which the JS engine completes its initialization.
Understand the benefits of the scope chain: If the scope chain is deeper, [0] => [1] => [2] => […] => [n], we call the global variable, it is always the last (here is the NTH), such a search to find the variable we need will cause much performance problems, so, try to local global variables, avoid layer upon layer nesting of the scope chain.
Understand the execution Context
- Add function before the function is called
[[Scope]]
Properties of theThe scope chainIt’s already there. - When this function is executed, a calledExecution contextAn internal object of execution Context. aExecution contextDefines the environment in which a function is executed, and creates one each time the function is calledExecution context; Once initializedExecution contextOn success, one will be createdActive objectsIt’s going to produce
this
arguments
And the variables that we declare, in this case, arex
,y
.
End the execution context phase
Relationship between scope chain and execution context
A scope chain is essentially a pointer to a list of variable objects. When a function is created, the Scope chain of the global variable object is added to the [[Scope]] property. When a function is called, an execution environment scope chain is created for the function, and an active object is created and pushed to the front of the execution environment scope chain. The variable object of the function local environment exists only during the execution of the function. In general, when the function completes, the local live object is destroyed and only the global scope is kept in memory. But closures are different.
Third, the closure
function createComparisonFunction(propertyName){
return function(object1,object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1 < value2){
return- 1; }else if(value1 > value2){
return 1;
}else{
return0; Var compareNames = createComparisonFunction('name'); Var result = compareNames({name:"Nicholas"},{name:"Greg"}); // Unreference anonymous functions compareNames = null;Copy the code
The relationship between the scope chains generated during the call to the compareNames() function is shown below
When createComparisonFunction completes, the scope chain of its execution environment is destroyed, but its active object is not destroyed because the anonymous function’s scope chain still references the active object. The active object of createComparisonFunction () is not destroyed until the anonymous function is destroyed.
Closures and variables
function createFunctions(){
var result = new Array();
for(var i = 0; i < 10; i++){
result[i] = function() {return i;
};
}
returnresult; } console.log(createFunctions()[0]()); / / 10Copy the code
In fact, every function returns 10. Reason: Because each function holds the live object of the createFunctions() function in its scope chain, they all refer to the same variable.
How do you make a closure print the desired result?
function createFunctions(){
var result = new Array();
for(var i = 0; i < 10; i++){
result[i] = function(num){
return function() {return num;
}
}(i);
}
return result;
}
for(var j = 0; j < 10; j++){
console.log(createFunctions()[j]());
}Copy the code
Instead of assigning the closure to an array, we define an anonymous function and pass the parameter to the anonymous function. Since the parameter is passed by value, we assign the current I value to num, and generate a closure within the anonymous function that returns num.