JavaScript是一种编译还是解释语言,还是两者都有?

9

非常抱歉我问了这个愚蠢的问题,但我对此感到困惑。

我一直在阅读一本名为you don't know JS yet的书籍,该书提到:

JS最准确地描述是编译语言。

他们用一些例子进行了解释,对我来说这很有道理。

但是当我在互联网上搜索时,大多数人都认为JS是一种解释性语言。 我读到了JS引擎使用许多技巧来处理JS程序,例如JIT、热重新编译等。

那么我应该把Javascript视为既编译又解释的语言吗?


@ImranRafiqRather,非常感谢您的回答。它显然对我有所帮助。我认为我应该继续搜索以获得更好的理解。 - Tu Le Thanh
在我看来,最好向ECMAscript而不是JavaScript提出这个问题。Ecmascript是一个实际的标准。另一方面,JavaScript就像有600种东西。 - ControlAltDel
3个回答

11

更新:

1995-96年,Brendan Eich创建了第一个JS引擎——spider-monkey(仍在Mozilla Firefox中使用),最初JavaScript是为浏览器设计的。因此,来自服务器的任何文件都可以快速解释并由浏览器显示。

解释器是这样做的最佳选择,因为解释器逐行执行代码并立即显示结果。

但随着时间的推移,性能成为一个问题,它变得越来越慢。解释器的问题在于当您在循环中运行相同的代码时:

const someCalculation = (num1, num2) => {
  return num1 + num2;
};

for (let i = 0; i < 10000; i++) {
  someCalculation(5, 6); // 11
}

它可能会变得非常慢。

因此,最好的选择是引入编译器,

这实际上对我们有所帮助。它需要更长的启动时间,因为它必须在开始时经过编译步骤-浏览我们的代码,理解它并将其吐出到另一种语言中。但编译器会很聪明。当它看到像上面那样的代码(我们循环并具有相同的输入,返回相同的输出),它实际上可以简化此代码,并且可以用函数的输出替换此函数而不是多次调用此函数。类似于这样的东西。

const someCalculation = (num1, num2) => {
  return num1 + num2;
};

for (let i = 0; i < 10000; i++) {
  11; // And it will  not call someCalculation again and again.
}

因为编译器不会在每次循环中重复翻译,所以从中生成的代码实际上更快。
而这些编译器所做的编辑被称为优化。
因此,Javascript结合了解释器和编译器的优点。因此,浏览器开始混合使用名为JIT-编译器的编译器进行即时编译,以使引擎更快。

V8-Engine

在这张图片中,你可以看到一个分析器,它会监视重复的代码并将其传递给编译器进行代码优化。

这意味着我们输入引擎的Javascript代码执行速度将逐渐提高,因为分析器和编译器不断更新和更改我们的字节码,以尽可能高效。因此,解释器允许我们立即运行代码,而分析器和编译器允许我们在运行时优化代码。

现在让我们得出一些结论:

既然我们知道JS引擎在内部是如何工作的,作为程序员,我们可以编写更多优化的代码 - 代码可以比我们常规的Javascript更快地被编译器接受和运行。然而

我们需要确保不要让编译器混淆-因为编译器并不完美,它可能会犯错误,并尝试优化恰好相反的代码。如果它犯了错并且做了一些意外的事情,它会执行称为取消优化的操作,这需要更长的时间才能将其还原回解释器。

现在有一个大问题: Javascript是一种解释性语言吗?

回答:是的,最初当Javascript第一次出现时,您有一个Javascript引擎(例如由Brenden Eich创建的Spider-Monkey),该引擎将Javascript解释为字节码,并且该Javascript引擎能够在我们的浏览器内运行,告诉我们的计算机应该做什么。
但现在情况已经发生了变化,我们不仅使用解释器,还使用编译器来优化我们的代码。因此,这是一个常见的误解。

当有人说Javascript是一种解释性语言时,是有一定道理的,但这取决于实现方式。您可以制作一个Javascript引擎的实现,它仅编译。从技术上讲,这都取决于实现方式。


4

Javascript最初是一种解释型语言。第一次遇到代码时,它会逐个读取标记并根据规范精确地执行它们。这是第0级。

如果某段代码经常被执行,比如说100次(具体数字取决于浏览器),则认为它是“热”的。浏览器将标记化和基本操作预先计算到稍微快一些的字节码中。在这个阶段,不做任何假设,字节码与原始代码完全等效。这是第1级。

如果代码被执行得更频繁,比如说10,000次,并且参数的类型始终相同,则可以执行进一步的编译步骤。许多JavaScript运算符根据类型执行完全不同的操作。每个运算符都有一些逻辑来检查要执行的运算符变体(例如添加或连接)。不同类型的对象需要分配不同数量的内存。在函数顶部执行一次类型检查并一次性分配所有内存要快得多。这是第2级。

根据浏览器的不同,可能会有更多的优化级别,通常是通过对参数进行更严格的假设。可能有更有效的整数加法。当然,如果您使用不同的变量类型调用函数,则浏览器必须再次执行未经优化的原始JS。

实用建议

所有这些都是在幕后发生的,作为程序员,您很可能永远不必担心这个问题。优化永远不会改变程序的“大O”速度,这通常是导致大多数慢软件的原因。通过确保最常调用的函数的参数类型一致,您可能能够稍微提高速度,但不值得麻烦。


所以,根据我的理解。JS引擎并不是逐行编译源代码并在完成后立即执行它。相反,在某些情况下,如果可能的话,它会编译多行代码以增加速度。这正确吗? - Tu Le Thanh
1
@TuLeThanh 正确 - mousetail

2

查阅MDN

这是你获取最准确信息的地方
引用MDN的说法:

JavaScript(JS)是一种轻量级、解释型或即时编译的编程语言。

基本上,由于JS在多个环境中使用,它可以是其中之一。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接