JavaScript是按设计解释的吗?


73

我对此问题持谨慎态度,因为它可能看起来过于挑剔。我刚刚打开了JavaScript:权威指南,它指出了第一章第一页的内容。

“ JavaScript是一种高级,动态,无类型的解释型编程语言”

因此,我是否认为解释部分是语言规范中的要求,还是在尊重一种语言及其多种实现之间的差异时说该语言是一种解释性编程语言是否会产生误导?

显然没有用于JavaScript的静态编译器-https: //stackoverflow.com/questions/1118138/is-there-a-native-machine-code-compiler-for-javascript,所以也许这只是对此的一种反映。


有一段时间的jscript.net类似于AS3 /“丢失的” ES4。它被字节码编译到CIL。

13
V8明确声称不是解释器,而是编译器。
pimvdb 2012年

@GGG JScript.Net仍然活着,而且...生病了。但是还活着。msdn.microsoft.com/en-us/library/72bd815a.aspx
Jetti 2012年

1
FWIW,“ untyped”位也不是完全正确
Rob Agar'3

在FF 3.5中回答该问题的那一年,Firefox才发布了第一个基于浏览器的JIT编译器,因此当时它可能尚未广为人知。我相信现代JIT实际上会在JS文档的第一遍上进行大量编译(或至少要进行编译前的准备),以进行诸如标识和缓存隔离到给定范围的方法之类的事情。
Erik Reppen 2013年

Answers:


50

因此,我是否认为解释部分是语言规范中的要求,还是在尊重一种语言及其多种实现之间的差异时说该语言是一种解释性编程语言是否会产生误导?

EcmaScript语言极客经常使用术语“ ES解释器”来指代EcmaScript的实现,但规范未使用该术语。该语言概述,特别介绍了解释无关的条款的语言:

ECMAScript是基于对象的:基本语言和宿主功能由对象提供,而ECMAScript程序是通信对象的群集。

因此,EcmaScript假定“主机环境”被定义为对象定义的提供者,包括所有允许I / O或与外界的任何其他链接,但不需要解释器的对象。

语言中的语句和表达式的语义是根据完成规范定义的,该规范在解释器中轻松实现,但该规范不要求这样做。

8.9完成规范类型

完成类型用于解释语句的行为(breakcontinuereturnthrow)来实现控制的非局部传输。Completion类型的值是形式(typevaluetarget)的三元组,其中typenormalbreakContinuereturnthrow之一value是任何ECMAScript语言值或emptytarget是任何ECMAScript标识符或空的

术语“突然完成”是指非正常类型的任何完成。

可以将控制的非本地传递转换为指令数组,并进行跳转,以实现本机或字节码编译。

“ EcmaScript Engine”可能是表达相同想法的更好方法。


显然没有用于JavaScript的静态编译器

这不是真的。V8“解释程序”在内部编译为本地代码,Rhino可以选择在内部编译为Java字节码,各种Mozilla解释程序({Trace,Spider,Jager} Monkey)使用JIT编译器。

V8

V8通过在执行之前将JavaScript编译为本机代码,而不是执行字节码或解释它,来提高性能。

犀牛

public final void setOptimizationLevel(int optimizationLevel)

设置当前的优化级别。优化级别应为-1到9之间的整数。任何负值将被解释为-1,任何大于9的值都将被解释为9。优化级别-1表示解释模式将始终为用过的。级别0到9表示可以生成类文件。更高的优化级别需要在编译时性能与运行时性能之间进行权衡。如果运行时不存在优化程序包,则不能将优化程序级别设置为大于-1。

TraceMonkey

TraceMonkey将本机代码编译添加到Mozilla的JavaScript®引擎(称为“ SpiderMonkey”)。它基于加州大学欧文分校(UC Irvine)开发的一种称为“跟踪树”的技术,并基于与Tamarin跟踪项目共享的代码和想法。最终结果是大大提高了浏览器镶边和网页内容的速度。


1
谢谢您的回答,它实际上回答了这个问题。我想关于没有静态编译的最后评论是引起嗡嗡声的是,哪些实现实际编译代码,哪些没有编译。我唯一感兴趣的是语句“ JavaScript是一种解释性语言”的有效性,考虑到实现的引用和规范缺乏定义,这似乎是错误的。不鼓励使用《权威指南》的第二段,但我想我会坚持下去。
马特·埃施

@ me232,该声明在2008年之前基本上是正确的。Rhino认为它不是主要的解释程序,因此很少有人会误以为是“权威指南”。我没有读过这本书,所以我无法评论这句话在整体质量上的代表性。
Mike Samuel'3

“静态编译器”的定义是什么。我认为定义意味着编译仅发生一次,并且您会得到一个静态(即不变)的位桶,然后执行。AFAIK这不是任何JavaScript引擎的工作方式。这就是为什么他们有de-optimization步骤。换句话说,JavaScript是由这些引擎编译的,但不是静态编译的。
gman

@ gman,Rhino的字节码生成器以这种方式工作。
Mike Samuel

AFAIK并非如此。Rhino可以包含其他JavaScript文件,这些文件必须在运行时进行编译。这不是静态并发症。
gman

20

Chrome中使用的V8 JavaScript VM不包含解释器。相反,它由两个编译器组成,并且可以即时编译代码。其中一个编译器运行速度很快,但生成的代码效率低下,另一个是优化编译器。

我能理解为什么有些人会认为这种“欺骗”,因为每次运行代码时V8都会将源代码作为输入,并且用户必须安装V8。但是考虑一个编译器,它会发出一个包含完整解释器和字节码的可执行文件。然后,您将有一个独立程序。只是效率不是很高。


19

用于脚本语言的JIT编译器的出现模糊了编译和解释之间的界限,以至于问题并不那么重要。它仅在引擎读取一行代码并立即执行时才解释吗?(Shell脚本通常仍以这种方式实现。)当引擎获取整个文件,立即将其编译为某个字节代码,然后解释该字节代码时,是否进行解释?(第一阶段Mozilla引擎以这种方式工作,CPython也是这样。)当引擎一次解析一个函数并将其JIT编译为本机代码时,它是否在解释?那些将整个文件编译为字节码,然后根据需要一次JIT一个功能的引擎呢?(如今,大多数脚本引擎都以这种方式工作,

编译和解释之间有许多阴影。

我认为对解释最有用的定义是“在执行时被送入程序的源代码,而没有单独的提前步骤”。根据此定义,所有JavaScript引擎都是解释器。但这当然不是解释的唯一可能定义。

但是JavaScript是为解释而设计的吗?在某种程度上,是的:它具有一个eval函数以及Function构造函数,您可以将程序代码作为将要执行的字符串给出。在运行时动态构造程序代码的能力要求引擎能够解释源代码。但这并不意味着您无法提前完成其他所有操作。即使使用C ++和C#之类的编译语言,您也可以获取源代码,将其在内存中编译为新的机器代码,然后执行该代码。甚至还有一些库:C ++中的LLVM + Clang和C#中的Roslyn项目。

同样,JavaScript的交付机制是源代码。没有公认的字节码形式。C#和Java有其官方字节码,每个人都希望C ++作为机器代码提供。但这不是语言的固有方面,而只是主要的使用场景。实际上,Flash中JavaScript的紧密相关ActionScript实际上是以字节代码形式提供的(Flash编译器会预编译所有脚本)。


4

关于“解释”与“编译”的定义尚无完全共识。与经典的区别是,编译语言生成独立的二进制可执行文件,而解释语言则需要部署的运行时来执行代码。虚拟机,字节码等模糊了区分。

但是这是一个可能有用的定义:解释语言是一种标准语言运行时能够将源代码文本作为输入并执行它的语言。通过该定义,可以解释Perl,Python,Ruby,JavaScript和Shell脚本等(即使它们使用字节码甚至本机代码之类的中间步骤)。Java,C#,C等不是。即使规范未使用确切的单词,JavaScript仍按定义进行解释。


嗯,我不喜欢将Java和C放在同一个类别中。也许更好的区别是,语言通常以(A)源代码,(B)中间代码或(C)机器代码的形式分发。例如,A = javascript,B = Java,C = C。
约翰·亨克尔

调用解释或编译的语言是不正确的。例如,根据该规则,您将同意C ++是编译语言,对吗?那么Cling呢,它执行c ++代码而不进行编译。“对此等进行解释(即使它们使用了字节码甚至本机代码之类的中间步骤)”对此,java也由其VM进行解释。
Abhinav Gauniyal
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.