Home >Web Front-end >JS Tutorial >Detailed explanation of how JavaScript works
#What is JavaScript?
Let’s confirm the definition of JavaScript: JavaScript is an interpreted dynamic language.
Interpreted languages exist relative to compiled languages. The source code is not directly compiled into target code, but converted into intermediate code, and then the interpreter interprets and runs the intermediate code.
Mainstream programming languages include compiled (such as C), interpreted (such as JavaScript), and semi-interpreted and semi-compiled (such as Java).
[Related course recommendations: JavaScript video tutorial]
How does the code run?
First let’s understand how the code runs.
We know that the code is executed by the CPU, and the current CPU cannot directly execute statements such as if...else
, it can only execute binary instructions. But binary instructions are really unfriendly to humans: it is difficult for us to quickly and accurately determine what a binary instruction 1000010010101001
represents? So scientists invented assembly language.
Assembly language
Assembly language is actually the mnemonic for binary instructions.
Assume that 10101010
represents a read memory operation, the memory address is 10101111
, and the register address is 11111010
, then the complete operation 101010101010111111111010
means reading the value of a certain memory address and loading it into a register. Assembly language does not change this operation method. It is just a mapping of binary instructions:
LD:10101010 id:10101111 R:11111010
In this way, the above instructions can be expressed as LD id R
, greatly enhances the readability of the code.
But this is not friendly enough. The CPU can only execute three-address expressions, which is far from human thinking and language patterns. So great scientists invented high-level languages.
High-Level Language
"The code is written for people to read, not for the machine to read. It is just that the computer can execute it."
The reason why high-level language is called "advanced" is because it is more in line with our thinking and reading habits. if…else
This kind of statement looks much more comfortable than 1010101010
. However, computers cannot directly execute high-level languages, so they need to convert high-level languages into assembly language/machine instructions before they can be executed. This process is compilation.
Does JavaScript need to be compiled?
JavaScript is undoubtedly a high-level language, so it definitely needs to be compiled before it can be executed. But why do we call it an interpreted language? What is the difference between it and compiled languages and semi-interpreted and semi-compiled languages? Let's start with compilation.
Compilation
We have already understood the concept of compilation before, let’s talk about the platform: The same C code will be compiled on Windows It becomes an .obj file, while on Linux it generates an .o file. The two cannot be used universally. This is because in addition to code, an executable file also requires system resources such as operating system APIs, memory, threads, and processes, and the implementations of different operating systems are also different. For example, the I/O multiplexing (the soul of event-driven) that we are familiar with, the implementation solution on Windows is the IOCP solution, and on Linux it is epoll. Therefore, compiled languages need to be compiled separately or even written separately for different platforms, and the generated executable files have different formats.
Cross-platform
Java goes one step further by introducing bytecode to achieve cross-platform operation: no matter what All .java files compiled on the operating system are .class files (this is a bytecode file, an intermediate form of target code). Then Java provides different Java virtual machines for different systems to interpret and execute bytecode files. Interpretation and execution does not generate object code, but it will eventually be converted into assembly/binary instructions for computer execution.
If we write a simple operating system completely independently, can it run Java? Obviously it's not possible, because there is no corresponding JVM for this system. Therefore, Java's cross-platform and any other language's cross-platform have limitations.
The advantage of Java using semi-interpreted and semi-compiled is that it greatly improves development efficiency, but correspondingly reduces the code execution efficiency. After all, virtual machines have performance losses.
Explanation and execution
JavaScript goes one step further. It is a completely interpreted execution, or just-in-time compilation. There will be no intermediate code generation, nor target code generation. This process is usually handled by the host environment (such as browser, Node.js).
Compilation process
现在我们确认了,即使是解释执行的语言,也是需要编译的。那么代码是如何编译的呢?我们来简单了解一下。
词法分析
词法分析会把语句分解成词法单元,即Token。
function square(n){ return n*n; }
这个函数会被词法分析器识别为function
,square
,(
,n
,)
,{
,return
,,n
,*
,n
,}
并且给它们加上标注,代表这是一个变量还是一个操作。
语法分析
这个过程会把Token转化成抽象语法树(AST):
{ type:'function', id:{ type:'id' name:'square' }, params:[ { type:'id', name:'n' } ] ... }
优化及代码生成
在这一步编译器会做一些优化工作,比如删除多余运算、删除未用赋值、合并部分变量等等操作,最后生成目标代码。
由于即时编译型语言的编译通常发生在运行前几微秒,所以编译器来不及做太多的优化工作。这也是相比编译型语言,早期JavaScript性能孱弱的原因之一。不过就现在而言,益于 V8 引擎(相比早期的JavaScript的引擎转换成字节码或解释执行,Node.js可以用 V8 提供的 JS2C 工具将 JavaScript 转译为 C++代码),JavaScript 和其他语言性能上的差距已经不足为道了。
链接及装载
目标代码基本不能独立运行。应用程序一般都会由多个部分(模块)组成 ,比如C++中一个简单的输出就要引入标准库 iostream
:
#include <iostream> using namespace std; int main(){ cout <p>编译器需要把多份目标代码(库)链接起来才能生成可执行文件。至此,我们简单的了解了编译过程。但实际上编译比我们所讲的要复杂得多,在此就不在展开了。</p> <p><strong><span style="font-size: 18px;">什么是动态语言,动态类型?</span></strong></p> <p>我们还知道,JavaScript是动态语言。那么什么是动态语言?</p> <p>通常来说,这是指在运行时代码可以根据某些条件改变自身结构的语言。比如JavaScript在运行时新的函数、对象、甚至代码都可以被引进(eval);又比如Objective-C,它也可以在运行时修改对象,但它不能动态创建类,也没有 eval 方法。那Objective-C算是动态语言吗?所以我认为,动态语言是个程度的问题,我们不必在这个概念上太过纠结,可以更多的关注其应用。APP中常用的热更新功能就是基于动态语言特性而得以实现的。</p> <p>JavaScript又是一门动态类型的语言,动态类型又是什么?动态类型的定义倒是很明确:数据类型不是在编译阶段确定,而是在运行时确定。</p> <p>那么 TypeScript 是什么类型的语言呢?它有静态类型检查,它是静态语言吗?实际上它只是 JavaScript 的一个方言。TypeScript 最终还是要转译为 JavaScript 才能执行(tsc),就如同我们使用babel 把 ES6 代码转译为 ES5 一样。这个过程严格上来说不是编译。</p> <p>TypeScript 最大的优势就是静态类型检查和类型推断,这是 JavaScript 严重缺失的能力。但实际上如果我们忽略IDE 给的报错提示强行运行 TS 代码,也还是有几率能够成功跑起来的。</p> <p><span style="font-size: 18px;"><strong>错误</strong></span></p> <p>刚刚我们提到报错,不妨再扩展说一说错误。通常来说错误分为以下几种:</p> <ul> <li>编译时错误</li> <li>链接时错误</li> <li>运行时错误</li> </ul> <p>是不是和编译过程能够严格对应起来?</p> <p><strong>编译时错误</strong></p> <p>编译时错误分为:</p> <ul> <li> <p>语法错误</p> <pre class="brush:php;toolbar:false">var str ='s ;
这就是典型的语法错误,这种代码无法生成AST,在词法分析阶段就会报错。通常我们这么写代码,IDE 就会报错。这是IDE的优化工作,和词法分析相关。
编译器会检查我们声明的变量和函数的类型,JavaScript中我们非常熟悉的Type Error:undefined is not object
就是此类错误。
链接时错误
在链接阶段发生的异常。这种情况 JavaScript 中比较少见,在编译型语言中比较常见。
运行时错误
这是最难排查的错误了,举例来说:
int pider(int a,int b){ return a/b; }
上面的代码在编辑编译、链接阶段都没问题,也能够正常的生成可执行文件。但是一旦如此使用pider(1,0)
就会报错了,这就是典型的运行时错误。通常来说运行时错误都是程序不够健壮导致的。
JavaScript中最常见的十个错误:
下图是某错误处理平台收集统计的JavaScript Top10 错误,其中7个TypeError,1个 ReferenceError:
#Obviously, we can use TypeScript to deal with these 8 problems in a timely manner in the early stages of coding.
Conclusion
Now we understand how JavaScript works. But can understanding this help us write better code?
The answer is yes. Not to mention that TypeScript can help us improve type checking and type inference. The scope and this of JavaScript are also strongly related to the compilation process; and the current mainstream small program frameworks can support one set of code and multiple platforms. I believe that after reading this article Finally, you have a general understanding of the principles behind these technologies.
Happy Hacking!
This article comes from the js tutorial column, welcome to learn!
The above is the detailed content of Detailed explanation of how JavaScript works. For more information, please follow other related articles on the PHP Chinese website!