资讯专栏INFORMATION COLUMN

JavaScript到底是解释型语言还是编译型语言?

gghyoo / 2268人阅读

摘要:编译型语言解释型语言主要问题是没有团体或者组织规定这些例如编译型语言和解释型语言的定义以及如何划分。下面是处理声明语句的过程一旦引擎进入一个执行具体代码的执行上下文函数,它就对代码进行词法分析或者分词。这是解释型语言需要的。

几天前一个刚接触 JavaScript 的朋友问我 JavaScript 是编译型语言还是解释型语言。从一个初学者那里听到这样的问题让我有些惊讶,因为所有初学者都知道 JS 是一个解释型语言;特别是像她这样之前使用过 Java 这类语言的初学者。

当一些人深入 JavaScript 并且开始研究 V8 引擎、SpiderMonkey、JIT 之类东西的时候,他们开始对于解释型还是编译型有更多的疑问。很高兴看到她已经在这个阶段了。

令人困惑的是什么?

最开始的时候,JavaScript 的圣经 —— MDN 明确地说 JavaScript 是一个解释型语言(同时还说到了 JIT 及时编译,后文会提及)。但是下面几点仍然会让 JavaScript 是否真的是一个解释型语言产生疑问:

如果 JS 是解释型语言那为什么会有变量提升(hoisting)?

JIT(及时编译)会做代码优化(同时创建代码的编译版本);解释型语言无法做到这些。

有什么快速的回答吗?

由于 JavaScript 规范没有对这一点做明确说明,困惑和疑问是都是存在的,不能片面地回答。让我们基于理论定义和 JavaScript 工作流程来弄清楚 JavaScript 到底是什么语言。

编译型语言 VS 解释型语言

主要问题是没有团体或者组织规定这些;例如:编译型语言和解释型语言的定义以及如何划分。 而这两个都是概念。

所以根据概念,编译型语言是代码在运行前编译器将人类可以理解的语言(编程语言)转换成机器可以理解的语言。

解释型语言也是人类可以理解的语言(编程语言),也需要转换成机器可以理解的语言才能执行,但是是在运行时转换的。所以执行前需要环境中安装了解释器;但是编译型语言编写的应用在编译后能直接运行。

许多人认为解释型语言意味着当遇到程序中行号为xyz时直接将其传给CPU就能运行;但是事实不是这样。所有的编程语言都是为人类创建的。他们是人类能够理解的。必须将编程语言转换为机器语言才能运行。编译器获取整个代码,转换它,做合适的优化并且创建一个可以运行的输出文件。编译器根据上下文来转换语句。

那么变量提升呢?

我觉得你应该已经知道了 JavaScript 的变量提升。在函数作用域内的任何变量的声明都会被提升到顶部并且值为undeinfed

所以 JavaScript 引擎好像解释了同一个脚本文件两次?第一次完成所有的声明提升然后第二次才执行代码?还是先编译整个代码然后运行它?这两种都不对。

下面是 JavaScript 处理声明语句的过程:

一旦 V8 引擎进入一个执行具体代码的执行上下文(函数),它就对代码进行词法分析或者分词。这意味着代码将被分割成像foo = 10这样的原子符号(atomic token)。

在对当前的整个作用域分析完成后,引擎将 token 解析翻译成一个AST(抽象语法树)。

引擎每次遇到声明语句,就会把声明传到作用域(scope)中创建一个绑定。每次声明都会为变量分配内存。只是分配内存,并不会修改源代码将变量声明语句提升。正如你所知道的,在JS中分配内存意味着将变量默认设为undefined

在这之后,引擎每一次遇到赋值或者取值,都会通过作用域(scope)查找绑定。如果在当前作用域中没有查找到就接着向上级作用域查找直到找到为止。

接着引擎生成 CPU 可以执行的机器码。

最后, 代码执行完毕。

所以变量提升不过是执行上下文的小把戏,而不是许多网站描述的源代码修改。在执行任何语句之前,解释器就要从创建执行上下文后已经存在的作用域(scope)中找到变量的值。

解释 JavaScript 中的即时编译(JIT)

JIT 或 及时编译 编译器不是 JavaScript 所特有的。其他语言比如 Java 也有一些在执行前编译代码的机制。

现代 JavaScript 引擎同样有 JIT。是的,它们有编译器。让我来为你解释一下为什么它们需要 JIT 以及 JIT 在 JavaScript 的执行中是如何工作的。

编译型和解释型语言最重要的区别是编译型语言需要很长的时间来准备执行。因为它需要对整个代码进行词法分析、做一些极致的优化等工作。另一方面解释型语言几乎在执行后一瞬间就开始,但是没有任何代码优化。所以每一条语句都是分开转换(编译)的,考虑下面这一段代码。

for(i=0; i < 1000; i++){
    sum += i;
}

在编译型语言中sum += i部分在循环运行时已经编译成了机器码,机器码将直接运行一千次。

但是在解释型语言中,执行时会将sum += i转换(编译)一千次。对相同的代码进行一千次转换会造成非常大的性能损耗。

这就是 Google 和 Mozilla 的开发人员将 JIT 加入 JavaScript 的原因。

编译

在 JavaScript 中如果一段代码运行超过一次,那么就称为 warm。如果一个函数开始变得 warmer(译者注:即运行更多次),JIT 将把这段代码送到编译器中编译并且保存一个编译后的版本。下一次同样代码执行的时候,引擎会跳过翻译过程直接使用编译后的版本。

这将优化性能。在真正的编译器中,因为编译器能访问整个代码所以做了除此之外更多的事情。

优化

如果一段 warm 的代码变得 hot 或者 hotter(译者注:指运行更多次以及比更多还要多的次数)JIT 会尝试更多的优化并且保存优化后的版本。在编译器进行优化的过程中会做一些关于变量类型和运行环境中值的假设,如果假设不成立就将这个优化的版本回退,如果假设成立的话,这将让代码性能更高。

想要了解更多 JIT 的知识可以阅读 Lin Clarks 关于JIT的课程。

总结

现在我们了解了 JavaScript 执行时到底发生了什么,所以应该可以区分 JavaScript 到底是编译型还是解释型语言了。下面是这篇文章的要点。

JavaScript 代码需要在机器(node 或者浏览器)上安装一个工具(JS 引擎)才能执行。这是解释型语言需要的。编译型语言程序能够自由地直接运行。

变量提升不是代码修改。在这个过程中没有生成中间代码。变量提升只是 JS 解释器处理事情的方式。

JIT 是唯一一点我们可以对 JavaScript 是否是一个解释型语言提出疑问的理由。但是 JIT 不是完整的编译器,它在执行前进行编译。而且 JIT 只是 Mozilla 和 Google 的开发人员为了提升浏览器性能才引入的。JavaScript 或 TC39 从来没有强制要求使用 JIT。

因此,虽然 JavaScript 执行时像是在编译或者像是一种编译和解释的混合,我仍然认为 JavaScript 是一个解释型语言或者是一个今天很多人说的混合型语言,而不是编译型语言。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107210.html

相关文章

  • Java到底编译语言解释语言

    摘要:编译型语言把做好的源程序全部编译成二进制代码的可运行程序。所以可是说即是编译型的,也是解释型,但是假如非要归类的话,从概念上的定义,恐怕应该归到解释型的语言中。编译型的语言包括解释型的语言包括 转载自网络 Java这个语言很神奇: 你可以说它是编译型的。因为所有的Java代码都是要编译的,.java不经过编译就什么用都没有。 你可以说它是解释型的。因为java代码编译后不能直接运行,...

    KavenFan 评论0 收藏0
  • JAVA到底编译语言解释语言?

    摘要:最后给出编译型语言和解释型语言的定义。定义编译型语言把做好的源程序全部编译成二进制代码的可运行程序。解释型语言把做好的源程序翻译一句,然后执行一句,直至结束特点编译型语言,执行速度快效率高依靠编译器跨平台性差。 有人说Java是编译型的。因为所有的Java代码都是要编译的,.java不经过编译就无法执行。 也有人说Java是解释型的。因为java代码编译后不能直接运行,它是解释运行在J...

    beanlam 评论0 收藏0
  • Python的发展历程

    摘要:可以脱离语言环境独立运行就像一本英文书,我找一个翻译,给他点时间,把英文书翻译成中文的,这就是编译型语言解释型语言有良好的平台兼容性,在任何环境中都可以运行,前提是安装了解释器虚拟机。就像还是一本英文书,我看一句让他给我解释一句。 写在前面 随着大数据、人工智能这类词汇扑向我们,python这个早在1989就已经出现的语言终于高调回归,为了更好的学习python 我们先来了解下它的前世...

    lovXin 评论0 收藏0
  • JavaScript编程全解 —— 基础

    摘要:函数式编程最后介绍一下函数式编程。函数式编程是一种历史悠久,而又在最近颇为热门的话题。函数式编程在面向对象一词诞生以前就已经存在,不过它在很长一段时间里都被隐藏于过程式编程面向对象也是过程式编程的一种的概念之下。 2.1 JavaScript特点 总结以下几个特点: 解释型语言 类似与C和Java的语法结构 动态语言 基于原型的面向对象 字面量的表现能力 函数式编程 解释型语言:...

    CoreDump 评论0 收藏0
  • 做一个好前端必须要知道的事——JS语言

    摘要:准确的理解,是编译型语言,源代码整个编译成字节码,字节码,是解释型语言。是一个非常灵活的语言,支持命令式和函数式编程。编译型语言通常会用做配置文件,因为我们通常不会改编译后的字节码。 编程语言按各种方法可以分为各种类型,现在让我们来看看JS属于什么类型语言 解释型语言 按编译执行过程,可以分为编译型语言和解释型语言。比如 c 语言,必须先经过编译生成目标文件,然后链接各个目标文件和库...

    Near_Li 评论0 收藏0

发表评论

0条评论

gghyoo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<