Mo Yanmei takes you to read the world of “JavaScript you Don’t Know” series, get inside the JavaScript language, figure out the use of every part of JavaScript, and know why.

takeaway

In Chapter 1, you learned about scopes, which are a set of rules that govern how the engine performs variable look-ups based on identifier names in the current scope as well as in nested subscopes.

There are two main working models of scope: lexical scope (JavaScript, etc.); The second is dynamic scoping (bash scripts, etc.).

Lexical scope

  • What is lexical scope
  • Why discard both mechanisms of spoofing lexical scope

2.1 Lexical stage

As you learned in Chapter 1, the first working stage of most standard language compilers is tokenization.

A lexical scope is a scope defined during lexical analysis, that is, when writing code, determined by the position of the variable and block scopes. Therefore, it is also fixed in lexical analysis (regardless of the spoofing lexical scope).

The following sample code has three nested scopes:

  • Circle 1 contains the global scope and only one identifierfoo
  • Circle 2 containsfooScope, with three identifiersabarb
  • Circle 3 containsbarScope, which has an identifierc

The scope is determined by where the scope code block is defined, where each function creates a scope.

Here scope nesting is strict; a function cannot exist in two external functions at the same time.

2.1.1 lookup

  • The scoped lookup stops when the first matching identifier is found.

  • Shadowing effect: Identifiers of the same name can be defined in multiple nested scopes. Internal identifiers mask external identifiers.

  • Global variables are properties of global objects. Overridden non-global objects cannot be accessed.

    window.a
    Copy the code
  • Lexical scoping lookup only looks for first-level identifiers, such as A, B, and C. If foo.bar.baz is referenced in your code, the lexical scope only looks for the foo identifier, and when found, the object property access rules take over access to the bar and baz properties, respectively.

2.2 Deception morphology

Spoofing lexical scope can lead to performance degradation, and neither of the following methods is recommended.

2.2.1 eval

  • eval(...)Functions can take a string as an argument and run the contents of the string as code to implement modifications to the lexical scope environment.
  • In the implementationeval()After that, the engine doesn’t know or care about the previous codeDynamic compilationandModify theThe lexical scope environment. The engine just does lexical scoping as it always does.
In non-strict mode:
function foo(a, str){
        console.log(str);           //2       // var b = 3;
	eval(str); / / cheating! console.log(eval(str));     //2      //undefined
	console.log(a, b);          //0   2  // 1  3
	console.log(a, window.b);   //0   2  //1  2
}
var b = 2;
foo(0, b);
foo(1, " var b = 3 ;"); 
Copy the code
  • eval()When called, the string argumentVar b = 3;Variable B is declared as real code and modifiedfoo()The lexical scope of infoo()A variable is created internallyb ,Overshadows a variable of the same name in an external global scopeb
  • console.log()When executed, will be infoo()The inside of theabBut you can never find an external oneb. So it will output1, 3“Instead of the normal output1 ,2

To expand the eval() function to understand the undefiend values, please click the following:

MDN parses the eval() case

Js eval ();

Use of the eval () function

In strict mode:
function foo(a, str){
    "use strict";
     console.log(str);           //2       // var b = 3;
     eval(str); 
     console.log(eval(str));    //2       //undefined
     console.log(a, b);         //0  2    // 1  2
     console.log(a, window.b);  //0  2    //1  2
}
var b = 2;
foo(0, b);
foo(1, " var b = 3 ;");
Copy the code
  • eval()In strict mode, it has its own lexical scope, and declarations in it cannot be scoped.
  • setTimeout(...)setInterval(...)The first argument to can be a string, the contents of which are interpreted as dynamically generated function code.Obsolete.
  • The constructornew Function()Can take a code string (the previous argument is the parameter of the newly generated function),Avoid the use of.

2.2.2 with

With is often used as a shortcut to repeatedly reference multiple properties in the same object, rather than the object itself.

var obj = { a:1, b:2, c:3 }; Obj. A = 2; obj.b = 3; obj.c = 4; // Simple shortcut with(obj){a = 3; b = 4; c = 5; }Copy the code

Not just a shortcut to property access. As follows:

functionfoo(obj){ with(obj){ a = 2; } } var o1 = { a : 3 }; var o2 = { b : 4 }; console.log(o1.a); //3 foo(o1); console.log(o1.a); //2 foo(o2); console.log(02.a); //undefined console.log(a); //2 -> < span style = "box-sizing: border-box! Important;Copy the code
  • o1Pass,withThe declared scope iso1a = 2Assignment operation foundo1.aAnd will be2Assign to it.
  • o2Once passed in, scopeo2There is noaProperty, then proceedLHSIdentifier lookup,o2The scope of,foo()The identifier was not found in either the scope or global scopeaSo that whena = 2When executed, a global variable is automatically created as a side effect (non-strict mode)aAnd will2Assigned toa, soo2.akeepundefined

In strict mode, the with statement is completely disabled, and eval() retains only core functionality, and is not recommended.

2.2.3 performance

The JavaScript engine performs various performance optimizations at compile time, some of which statically analyze the code during lexical analysis, pre-positioning variable and function declarations so that identifiers can be quickly resolved during execution.

2.3 summary

The lexical scope is determined only by the position at which the function is declared.

The following two mechanisms can trick lexical scopes:

  • eval(...): For a paragraph containing one or more declarationscodeString to modify the existing lexical scope (The runtime).
  • with: Refers to an objectAs aScope, creating a new lexical scope by treating the attributes of the object as the scope identifier.The runtime).

The side effect is that the engine cannot optimize scoped lookups at compile time. Because the engine can only discreetly assume that such optimizations are ineffective, using either mechanism will cause the code to run slower. Discard them.

Finally, reading is a two-way process from thick to thin, and from thin to thick. It pays attention to comprehension and practice, and keeps stepping on pits and improving. If it is helpful, please click a compliment, thank you for your support and advice.

References:

Wood yi Yang blog

Gap swim dust blog

Taopoppy blog

Historical articles:

Read JavaScript you Don’t Know, Volume 1. What is scope 1-1

30 Seconds of ES6 (一)