This is the 17th day of my participation in the August Text Challenge.More challenges in August

compile

A piece of source code in a program goes through three steps before execution:

  • Word segmentation/lexical analysis
  • Parsing/parsing
  • Code generation

Lexical analysis

This process breaks down a string of characters into blocks of code that make sense (to the programming language), called lexical units (tokens). For example, consider the program var a = 2; . The program is usually broken down into the following lexical units: var, a, =, 2; . Whether Spaces are considered lexical units depends on whether they make sense in the language.

Syntax analysis

This process converts a stream of lexical units (arrays) into a hierarchical nested tree of elements that represents the syntactic structure of the program. This tree is called an Abstract SyntaxTree (AST). var a = 2; The abstract syntax tree may have a top-level node called VariableDeclaration, followed by a child node called Identifier (whose value is A), and a child node called AssignmentExpression. The AssignmentExpression node has a child called NumericLiteral (whose value is 2).

Code generation

The process of transforming an AST into executable code is called code generation. This process depends on language, target platform, and so on. Regardless of the details, the short answer is that there is some way to set var a = 2; The AST is converted to a set of machine directives that create a variable called A (including allocating memory, etc.) and store a value in A.

These are the three steps your code must go through in the compiler, but a JavaScript engine is much more complex. For example, there are specific steps in the parsing and code generation phases to optimize runtime performance, including for redundant elements.

Scope understanding

For code that operates on variables, the compiler queries the scope chain for whether the variable has been created according to specific rules.

  • LHS queryOccurs when a variable appears to the left of an assignment operation
  • RHS queryOccurs when a variable appears to the right of an assignment

Take a chestnut

function foo(a) { 
 console.log( a ); / / 2
} 
foo( 2 );
Copy the code
  • The last linefoo(..)The call to the function requires thefooforRHSThe query
  • fooIn a function declarationa = 2Is an implicitLHSThe query,2Is passed as a parameter tofoo(..)Function,2Will be assigned to parametersa
  • console.log( a )forconsoleThe object ofRHSQuery and check if any of the resulting values is calledlogThe method of

Scope nesting

Nesting of scopes occurs when a block or function is nested within another block or function. Therefore, when a variable cannot be found in the current scope, the engine will continue searching in the outer nested scope until it finds the variable or reaches the outermost scope (that is, the global scope).

The rule for traversing a nested scope chain is simple: The engine looks for variables starting at the current execution scope, and if it doesn’t find any, it continues up one level. When the outermost global scope is reached, the search process stops whether it is found or not.

abnormal

It is important to distinguish between LHS and RHS correctly

The two queries behave differently when the variable has not yet been declared (it cannot be found in any scope).

function foo(a) { 
  // the current scope, b is not created, engine back to the previous scope to find
 console.log( a + b ); 
 b = a; 
} 
// Here is the top-level scope
// If the engine still does not find B, a variable b individual engine is created in the global scope
// Only in non-strict mode
foo( 2 );
Copy the code

Instead of creating and returning a global variable when an LHS query fails in strict mode, the engine throws a ReferenceError exception similar to that when an RHS query fails.

If an RHS query finds a variable and you try to manipulate the value of the variable improperly, such as trying to make a function call on a value that is not of a function type, or referring to an attribute in a value of type null or undefined, the engine will raise another type of exception called TypeError.

ReferenceError indicates that the related variable was not found in the scope chain, and TypeError indicates that the related variable exists in the scope chain, but was improperly operated on, that is, an operation was performed on the variable that did not correspond to its type.

conclusion

  • This is used if the purpose of the lookup is to assign a value to a variableLHSThe query
  • Used if the purpose is to get the value of a variableRHSThe query
  • The assignment operator causesLHSThe query
  • =The operator causes bothLHSQueries can also lead toRHSThe query
  • LHSRHSThe query will start in the current execution scope
  • If the relevant variable is not found in the current scope, it is queried one level up, all the way to the top-level scope
  • After reaching the top-level scope, in non-strict mode, the related global variable cannot be found, and in strict mode, the related global variable will be generated automaticallyReferenceError
  • When a query reaches the top-level scope, it stops regardless of the result of the query.