javascript series you don't know (scope)

First, the understanding of javascript scope

 

  • 1. What is scope

   (1) Scope is a set of rules for finding variables by name. If the purpose of the lookup is to assign a value to a variable, the LHS query is used; if the purpose is to obtain the value of the variable, the RHS query is used.

   (2) When a variable cannot be found in the current scope, it will continue to search in the outer nested scope until it finds or reaches the outermost scope (global scope). 

Such as:

function foo(a){

console.log(a+b);//b cannot be found in the function scope, b=2 can be found in the upper scope;

}

var b=2;//outer scope

foo(2);//4

   (3) An unsuccessful RHS reference will cause a ReferenceError exception to be thrown; an unsuccessful LHS reference will automatically and implicitly create a global variable (in non-strict mode) that uses the target of the LHS reference as an identifier, or Throws a ReferenceError exception (in strict mode)

 

  • 2. Lexical scope

Scope is divided into lexical scope and dynamic scope

   (1) The lexical scope is the scope defined in the lexical phase. In other words, lexical scope is determined by where you write variable and block scope when you write code.

Such as:

  function foo(a){

var b=a*2;

function bar(){

console.log(a,b,c);

}

bar (b * 3);

          }

 

foo(2);//final output 2,4,12

       illustrate:

The outermost layer contains the entire global scope, with only one identifier: foo.

 

The foo layer contains the created scope, with three identifiers a, bar, b.

The bar layer contains the created scope with only one identifier c.

    (2) Deception lexical There are two mechanisms to "modify" the lexical scope at runtime, one is to use the eval() function, and the other is to use the with statement. But both methods are deprecated, cheating lexical scoping can lead to performance degradation.

Such as:

function(str,a){

eval(str);//Deception, will block the outer var b=2; define b as 3

console.log(a,b);//1,3

}

         var b=2;

foo("var b=3;",1);

with essentially creates a new lexical scope (at runtime) by treating an object's reference as a scope and an object's property as a scope's identifier.

The side effect of these two mechanisms is that the engine can no longer optimize the scope lookup at compile time, which will cause the code to run slower. Don't use them.

 

 

  • 3. Function and block scope

(1) Function scope means that all variables belonging to this function can be used and reused within the scope of the entire function.

Adding a wrapper function outside any code fragment can "hide" the internal variables and function definitions, and the outer scope cannot access any content inside the wrapper function.

Such as:

var a=2;

function foo(){

var a=3;

console.log(a);//3 accesses the internal variable a of the foo function. If a is not defined inside the foo function, access the external var a=2.

}

foo();

console.log(a);//2 accesses the global variable a, cannot access the variable var a=3 in the foo function

(2), function expression 

(function foo(){

var a=3;

})();

Being a function expression means that foo can only be accessed in the represented location, not the outer scope. A function is enclosed within a pair of ( ) parentheses, thus becoming an expression, which can be executed immediately by appending another ( ) to the end.

(3), block scope

Block scope is that only variables are valid within a block of code.

The most familiar block scope:

for(var i=0;i<10;i++){

console.log(i);//0,1,2,3,4,5,6,7,8,9

}

console.log(i);//10

It can be seen that i is not valid in the for block and can still be accessed in the outer scope. The same is true for the variables defined in the if block, so what is the block scope?

 

a, the scope created from the with object

b. The catch clause of try/catch creates a block scope in which the declared variables are only valid inside the catch.

Such as:

try{

undefined();//Perform an illegal operation to force an exception to be thrown

}catch(err){

console.log(err);//Print error message normally

}

console.log(err);//ReferenceError:err not found

c. let keyword

 The let keyword can bind a variable to any scope it is in. Usually {} inside.

 Look back at the code block of the for loop: change var to let to define i

for(let i=0;i<10;i++){

console.log(i);//normal output

}

console.log( i);//

ReferenceError: i is not defined can not be referenced from the outer layer, i is only valid in the for code block.

d. const can also be used to create block scope variables, but their values ​​are fixed (constants)

 

  • 4. Scope Closure

(1), what is a closure? A closure occurs when a function can remember and access the lexical scope it is in, even if the function executes outside the current lexical scope. (functions that can read variables inside other functions)

 

Such as:

function foo(){

var a=2;

function baz(){

console.log(a);//2

}

bar (bases);

}

 

function bar(fn){

fn();//Mom, look! This is the closure

};

 

Whenever you use a callback function, you are actually using a closure.

(2), closure and loop

A for loop is the most common example:

for(var i=1;i<=5;i++){

setTimeout(function(){

console.log(i);// output 5 times 6

},i*1000);

}

The expected situation is to output 1~5 respectively, once per second, one at a time.

In reality, 6 is output once per second.

Because, trying to assume that each iteration in the loop "captures" itself a copy of i at runtime, but according to how scope works, the reality is that although the five functions in the loop are defined separately in each iteration,

But they're all enclosed in a shared global scope, so there's really only one i.

 

To output as expected requires its own variable to store the value of i in each iteration:

for(var i=1;i<=5;i++){

(function(){

var j = i;

setTimeout(function(){

console.log(j);

},j*1000);

})();

}

 

Or you can use let block scope

 

for(let i=1;i<=5;i++){

setTimeout(function(){

console.log(i);

},i*1000);

}

 

(3), module

Module mode requires two prerequisites:

1. There must be an external enclosing function, which must be called at least once (each call creates a new module instance);

2. The enclosing function must return at least one inner function, so that the inner function can form a closure in the private scope and can access or modify the private state.

Such as:

var foo = (function CoolModule(id){

function change(){

publicAPI.identify = identify2;

}

 

function identify1(){

console.log(id);

}

function identify2(){

console.log(id.toUpperCase());

}

 

var publicAPI = {

change:change,

identify:identify1

}

return publicAPI;

})("foo module");

foo.identify();//foo module

foo.change();

foo.identify();//FOO MODULE

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326509903&siteId=291194637