JavaScript lexical scopes (JavaScript you Don't know)
JavaScript is not a traditional block-level scope, but a function scope!
I. Scope 1. the JavaScript engine will compile the code before execution. In this process, declarations such as var a = 2 will be divided into two independent steps:
Step 1 (compilation phase): var a declares new variables in its scope. This will be performed in the initial stage, that is, before code execution.
Step 2 (running phase): a = 2 queries the variable a (LHS query) and assigns values to it.
2. LHS & RHS (current scope-> upper-level scope->...-> global scope)
LHS (left side): Try to find the variable container itself
RHS (right side): Find the value of a Variable
Example:
Function foo (a) {var B = a; return a + B;} var c = foo (2); // LHS (3): c; a (implicit Variable Allocation); B; // RHS (4 places): foo (2); = a; B;
3. Exceptions
function foo(a){console.log(a + b);b = a;}foo(2);
(1) In ES5 "strict mode", LHS throws a ReferenceError. In "non-strict mode", LHS automatically and implicitly creates a global variable.
(2) A ReferenceError is thrown when RHS queries fail to traverse all nested scopes.
(3) RHS queries a variable, but if you try to operate it unreasonably (reference a property in the null or undefined type), a TypeError will be thrown.
In a word, ReferenceError is related to failure in scope discrimination. TypeError indicates that the scope discrimination is successful, but the operation on the result is illegal or unreasonable.
PS: in principle, I elaborated on the JavaScript function and prototype function execution overwrite in my blog !!!
2. Lexical scope the lexical scope means that the scope is determined by the position of the function declaration during code writing. JavaScript has two mechanisms to "cheat" the lexical scopes: eval (...) and.
1. eval
The eval function can accept a string parameter and regard the content as code that appears in the position of the Program During writing (code can be generated and run at the current position ).
Eval can calculate a piece of "code" string containing one or more declarations and modify the existing lexical scope (runtime stage ).
function foo(str,a){eval(str);console.log(a, b);//1 , 3console.log(a, window.b);//1 , 2}var b = 2;foo("var b = 3;", 1);
Explanation: The above global variable B is overwritten. Because B is global, it can be obtained through window. B. If a non-global variable is overwritten, it cannot be accessed!
In strict mode:
function foo(str,a){"use strict";eval(str);console.log(a, b);//1 , 2console.log(a, window.b);//1 , 2}var b = 2;foo("var b = 3;", 1);
2.
With is usually used as a shortcut to repeatedly reference multiple attributes of an object. You do not need to repeat the object itself.
With processes the object attributes as the identifiers in the scope, and creates a new lexical scope (runtime stage ).
Function foo (obj) {with (obj) {a = 2 ;}} var o1 = {a: 3 }; var o2 = {B: 3 }; foo (o1 ); console. log (o1.a); // 2foo (o2); console. log (o2.a); // undefinedconsole. log (a); // 2, indicating that a is leaked to the global scope!
The side effect of these two mechanisms is that the engine cannot optimize the scope search during compilation, resulting in slow code running. We recommend that you do not use them!
PS: explains the reason why "with" cannot be used in "the essence of JavaScript language", "dregs" and "cancer !!!
Iii. Function scope and block Scope 1. Anonymous and named
/* Anonymous (reference itself can only be referenced with expired arguments. callee) */setTimeout (function () {console. log ("I wait 1 second! ")}, 1000);/* Name (good readability) */setTimeout (function timeoutHandler () {console. log (" I wait 1 seco nd! ")}, 1000 );
2. Execute the function expression immediately.
/* IIFE mode */var a = 2; (function IIFE (global) {var a = 3; console. log (a); // 3console. log (global. a); // 2}) (window);/* UMD mode */var B = 2; (function UMD (def) {def (window );}) (function tmpF (global) {var B = 3; console. log (B); // 3console. log (global. b); // 2 });
3. Block Scope
Try/catch creates a block scope.
Try {undefined ();} catch (err) {console. log (err); // can be used normally} console. log (err); // ReferenceError: err is not defined/* Pit 1 */for (var I = 0; I <10; I ++) {} console. log (I); // 10/* pit 2 */{console. log (bar); // undefined will not report an error !! Var bar = 2 ;}
Introduce the New let keyword in ES6 !!
/* Fill in 1 */for (let I = 0; I <10; I ++) {} console. log (I); // SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode/* fill in 2 */{console. log (bar); // SyntaxError !! Let bar = 2 ;}
We recommend two tools to convert ES6 code into an environment compatible with ES6 (most of which are ES5, but not all): Traceur and let-er