One, the introduction
Understanding the running mechanism of JS helps us to write high-quality code, reduce bugs and save maintenance costs in our daily work. It also helps us pass the interview to build the rocket.
- Understand JavaScript engines.
- Scope and scope chain through the operation mechanism.
- Understand the binding and priority of this through the runtime mechanism.
- Understand closures by their runtime mechanism.
Second, the rendering Engine | JavaScript Engine (JavaScript Engine)
Before we get to the mechanics, let’s clear up a few basic concepts.
2.1 Rendering Engine
Rendering is the process of building a data model and generating graphics based on descriptions or definitions. The rendering engine builds page resources (HTML, CSS, javaScript, etc.) into visual, audible multimedia results. That’s what we see in the browser rendering.
2.2 JavaScript engine
When we run a piece of code, it’s the JavaScript engine that really brings that code to life. A JavaScript engine is a virtual machine that specializes in JavaScript scripts and is typically shipped with a Web browser. The JavaScript engine is responsible for compiling and executing the entire JavaScript program from start to finish.
2.2.1 There are many types of JavaScript engines
The best known engine is the V8 engine used in Chrome and Node.
- V8 – Open source, developed by Google and written in C ++.
- Rhino – Managed by the Mozilla Foundation, open source and developed entirely in Java.
- SpiderMonkey – The first JavaScript engine to support Netscape Navigator, currently available for Firefox.
- JavaScriptCore – Open source, sold as Nitro, developed by Apple for Safari.
- KJS – Engine for KDE, originally developed by Harri Porten for the Konqueror web browser in the KDE project.
- Chakra (JScript9) — Internet Explorer.
- Chakra (JavaScript) — Microsoft Edge.
- Nashorn, as part of the OpenJDK, is written by the Oracle Java Language and tools group.
- JerryScript — A lightweight engine for the Internet of Things.
2.3 The relationship between rendering engines and JavaScript engines
- The rendering engine handles JavaScript logic by calling interfaces.
- JavaScript accesses elements such as the DOM of the rendering engine through a bridge interface.
3. JavaScript Runtime
If you want to make a piece of JavaScript code truly lucky, it is not enough to rely on a JavaScript Engine alone. JavaScript Engine’s job is to compile and execute JavaScript code, complete memory allocation, garbage collection, etc., but it lacks the ability to interact with the outside world.
For example, a V8 engine alone cannot make Ajax requests, set timers, respond to events, etc. This requires the help of JavaScript Runtime, which provides objects or mechanisms for JavaScript to interact with the outside world.
For example, although Chrome and Node both run V8 engines, their runtimes are different, such as process and FS browsers.
The execution of a piece of javaScript code can be divided into two phases.
Four, the two stages of JavaScript operation
4.1 Compilation Phase
- Word segmentation/lexical analysis
- Parsing/parsing
- Precompilation (code generation, interpretation phase)
4.2 Execution Phase
- JavaScript does not simply interpret executing code line by line, but rather breaks JavaScript into executable code blocks for execution. There are three types of code blocks in JavaScript.
2 blocks of code
- Code can be executed globally.
- Function executable code.
- Eval executable code.
Now we’re going to focus on the execution phase of JavaScript.
5. JavaScript execution
JavaScript is both a compiled and interpreted language. The JavaScript engine actually compiles the code just a few microseconds before executing it.
It’s called JIT (Just-in-time compilation). It’s a big topic in its own right. But for now, we can skip the theory behind compilation and focus only on the execution phase, which is still interesting.
A JavaScript engine that compiles and interprets our JavaScript code. JavaScript engines actually contain many smaller parts that work together to make JavaScript work.
- Global Memory
- Call Stack
- Execution context
- And so on and other components
5.1 Global Memory
Let’s take a look at some code
var num = 2;
function pow(num) {
return num * num;
}
Copy the code
So if you look at this code, think about what’s going to happen. You might already think of JavaScript engines that put references into Global Memory as soon as the first line of code is executed. Global memory is where the JavaScript engine holds variables and functions. When the engine reads the above code, global memory fills two bindings:
5.2 Call Stack
var num = 2;
function pow(num) {
return num * num;
}
pow(num);
Copy the code
When we execute a function, the JavaScript engine uses the Call Stack. The call stack is a stack class data structure, meaning it is a first-in-last-out mode of execution. If there are multiple functions, they are pushed one after the other.
When a block of code is executing, the JavaScript engine creates an execution context that serves as the base runtime environment for the code to run.
Execution context
In “4.2.1 Code Blocks “, there are three types of code blocks, each corresponding to three execution contexts
- Globally executable code => global execution context.
- Function executable code => function execution context.
- Eval Executable code => Eval execution context.
6.1 Global Execution Context
Basic execution context, a program has only one global execution context, any code that is not inside a function is in the global execution context. The global execution context only does two things:
- Create a global Window object (in the browser case).
- Set this to be equal to the global object.
6.2 Function execution Context
What if our function has some nested variables or one or more internal functions?
var num = 2;
function pow(num) {
var a = 1,
b = 2,
c = 3;
function add(a, b, c) {
returna + b + c; }}Copy the code
Each time a function is called, a new context is created for the function. Each function has its own execution context, but is created when the function is called. There can be any number of function contexts. Whenever a new execution context is created.
6.3 Eval Execution context
Code executed inside Eval also has its own execution context, so don’t, don’t, don’t use it lightly.
Execution contexts are also divided into creation and execution phases. It gets really interesting in the creation phase.
Create execution context
The creation phase of the execution context does three things:
- Decide on the binding of this.
- Create a lexical environment.
- Create the variable environment.
7.1 this binding
When the executable context is created, the default binding, implicit binding, display binding and so on are judged according to the execution conditions of the code.
7.1.1 This Binding classification
- Normal function calls: this points to the window(browser environment).
- Object method invocation: this refers to the calling object. (Implicit binding)
- Constructor: This points to the constructor instance.
- Apply, call, bind: this points to the binding value. (Show binding)
- Arrow function this: this points to the this of the first ordinary function call in the outer layer. (Default binding)
7.1.2 This Binding priority
The this binding also has precedence, as follows:
- Does the function have a new binding call: if so, this is bound to the newly created object.
- Whether the function shows binding via apply, call, or bind: if so, this is bound to the specified object.
- Whether the function is called implicitly in an object method: if so, this is bound to the calling object.
- In strict mode, this is bound to undefined; in non-strict mode, this is bound to global objects.
7.2 Lexical Environment
Lexical environments are used internally by JavaScript engines to track the mapping between identifiers and specific variables. Lexical environment is the implementation mechanism of Js scope. The concept of scope is similar to the concept of lexical context if you have seen it before (ES6 has changed the concept of scope to lexical context).
A scope is an independent domain that keeps variables from leaking and being exposed. In other words, the greatest use of a scope is to isolate variables. Variables of the same name in different scopes do not conflict. Before ES6, JavaScript had no block-level scope, only global scope and function scope. With the advent of ES6, we have ‘block-level scope’, which can be embodied by the addition of the let and const commands.
7.2.1 Lexical environment classification
- Global: The external reference to the global environment is NULL, which has built-in objects such as Object/Array/, prototype functions in the environment logger, and defined global variables.
- Module environment: The external environment reference of a module environment is the global environment (Window, browser environment), which has bindings declared at the top level of the module, and bindings imported explicitly by the module.
- Function context: A reference to a function context can be another function context or a global context. It has declared variables and functions.
7.2.2 Lexical environment composition
- A reference to the outer Lexical Environment: means that it has access to its parent Lexical Environment (the scope).
- Environment Record: The actual location where variable and function declarations are stored. Declarative environment loggers and object environment loggers are the two main environment loggers.
The lexical environment contains references to the external lexical environment, through which we can get variables, declarations, and so on from the external lexical environment. These references are concatenated to the global lexical environment, thus forming scope chains.
The lexical environment contains references to the lexical environment, which we can use to get variables, declarations, and so on from the lexical environment, thus forming closures.
7.3 Variable Environment
View a lot of data without detailed documentation of the variable environment.
As specified in the ES5 standard documentation, the execution environment includes: lexical environment, variable environment, and this binding. Where the lexical environment and variable environment components of the execution environment are always lexical environment objects. When you create an execution environment, the lexical environment component and the variable environment component start with the same value. The variable environment component never changes during the execution of the code associated with the execution environment, while the lexical environment component may change.
The invariant variable environment and the possible change of lexical environment are both guideline changes. The sections 12.10 and 12.14 of the specifications mention lexical environment changes in with and catch blocks.
Summary of the execution process of JavaScript
Nine, preview the overall process, this article only covered part of the
JavaScript is both a compiled and interpreted language. But JavaScript is essentially an interpreted language, and unlike compiled languages, which need to be parsed as they go along, compiled languages are already compiled at execution time, can be executed directly, and have faster execution speeds.
Reference:
- JavaScript – V8 engine
- Priority of the javascript-this binding
- How JavaScript works
- JavaScript Engines: How Do They Even Work? From Call Stack to Promise, (almost) Everything You Need to Know