# 2.为什么 js 是边解释边执行
转自:锐基同学的语雀
# 面试官:怎么理解 JS 边解释边执行?
阿里一面被面试官问了这个问题,问我为什么单线程还是可以答的上的,但问了我这个,一时哑口无言。这是我最常用的语言, but
了解的还是不够深。
为了理解这个问题,我先去找了 JavaScript
的解释:
# 什么是 JavaScript
维基百科 (opens new window) :JS 是一种高级的、解释型的编程语言。JavaScript 是一门基于原型、函数先行的语言,是一门多范式的语言,它支持面向对象程序设计,命令式编程,以及函数式编程。
在客户端,JS 在传统意义上被实现为一种解释语言,但最近它已经可以被即时编译(JIT)执行。
这里涉及到了关键词“解释型”,那么问题就来了,什么是“解释型”的编程语言?
# 什么解释型?
于是我接着在维基百科搜到:
解释型语言是一种编程语言的类型。这种类型的编程语言,将会代码一句一句直接运行,不需要像编译语言一样,经过编译器先行编译为机器代码,之后再运行。
这种变成语言需要利用解释器,在运行期,动态将代码逐句解释为机器码,或是已经预先编译为机器代码的子程序,之后再运行。
我又纳闷了,解释器又是什么呢?那编译语言又和解释型语言有什么区别呢?
层层递进,我又去找了相关的资料。
# 解释器是什么?
- 解释器,是一种计算机程序,能够把解释型语言解释执行,就像一位“中间人”。
- 解释器边解释边执行,因此依赖于解释器的程序运行速度比较缓慢。
- 解释器的好处就是它不需要重新编译整个程序,从而减轻了每次程序更新后编译的负担。相对的编译器一次性将所有源代码编译成二进制文件,执行时则无需依赖编译器或其他额外的程序。
解释器执行程序的方法有:
- 直接执行高级编程语言(如
Shell
内建的编译器 - 转换高级变成语言到更有效率的字节码,并执行字节码
- 用解释器包含的编译器对高级语言进行编译,并指示中央处理器执行编译后的程序(如:JIT)
JIT 即 just-in-time compilation,又译为即时编译、实时编译、动态翻译或运行时编译,是一种执行计算机代码的方法,它涉及在程序执行过程中(运行期)而不是在执行之前进行编译。通常,这包括源代码或更常见的字节码到机器码的转换,然后直接执行。
实现
JIT
编译器的系统通常会不断地分析正在执行的代码,并确定代码的某些部分,在这些部分中,编译或重新编译所获得的加速将超过编译该代码的开销。它的应用有如:正则表达式等
使用解释器来运行程序会比直接运行编译过的机器代码来得慢,但是相对的这个解释的行为会比编译再运行来得快。因为解释器每次都必须去分析并翻译它运行到的程序行,而编译过的程序就只是直接执行。
Chrome 的 V8 引擎在运行之前将 JS 编译成了机器代码,而非字节码或是解释执行它,以此提升性能。
- JS 的文本块或文件被解析成 一个
AST
语法树- 解释器解释执行,现在一般先从
AST
输出一个字节码序列;也有直接从AST
上进行解释和计算的- 对于热点代码,会有
JIT
编译器从字节码出发,编译到内部的IR
,做一些优化,生成机器码。
- 字节码:通常指的是已经经过编译,但与特定机器码无关,需要直译器转译后才能成为机器码的中间代码。如图
总而言之,解释器就是一个可以把解释型语言(JS 等)解释执行的一种计算机程序。
解决了解释器的问题,那么解释执行和编译执行又有什么区别呢?根据上面的一些描述,想必你们心中也有一定的答案了,下面做一下总结,真不容易阿 😭
# 解释执行和编译执行的区别
- 编译执行:顾名思义要先编译再执行,这里需要一个编译器来讲代码全部编译成机器码,然后直接进行执行。
- 解释执行:它则需要一个解释器,它会将我们的一句句解释成机器代码来执行,可以认为解释一句,执行一句。也不会生成中间文件。
对比可发现:
- 编译执行需要编译一次,就可以多次运行;而解释执行,每一次运行程序,都要经过解释器的解释过程。
针对优缺点可以从以下几个方面分析:
- 从启动效率来看,解释执行不需要进行编译操作,而编译执行要经过编译。因此解释执行启动速度更快!
- 从运行效率来看,因为编译执行只需要编译一次,以后在运行就无需编译,而解释执行每次都要经过解释过程,所以编译执行的运行效率更高!
- 从内存使用方面来看,编译执行需要生成机器码文件,而解释执行时逐句解释执行,所以解释执行对内存占用更少。
- 从跨平台的角度来看,因为解释执行每次可以根据不同的平台进行解释,例如
js
在linux
和windows
都可以运行,而C
在windows
下编译后的文件只能在windows
下才能执行。
知道了上面这些概念之后,再来问:你是怎么理解边解释边执行的,是不是已经有头绪了?