角度编译器“编译”什么?


88

今天有人问我,我无法给出适当的答案。

Typescript转换为JS。然后是摇晃的树,“较少”(可选)以及进行部署的过程。但是,那样的东西(afaik)与“编译”没有任何关系。一切都捆绑在一起并进行了严格的优化,但是实际上并没有被编译,对吗?

甚至还有一个“提前”编译器,它确实可以做得很出色。我想念什么?

JavaScript本身仍在解释,对吗?


6
我同意“不是真的编译”。从本质上讲,这是一个定义的编译问题。有些人更喜欢使用单词transpilation来标记从TypeScript到JavaScript的转换。但是,从本质上讲,Typescript编译器的作用只是从Typescript生成Javascript。
Pac0

6
@ Pac0我可能在这里误解了一些东西,但是如果将TypeScript转换为JavaScript,是否会将GCC转换为C到机器码的编译器?您将如何定义编译器和编译器之间的区别?
7684年

24
编译器是编译器
user253751 '10

5
看到人们说“翻译”是什么意思?(以及后续的“我的前15个编译器”)(来自从事编译器工作的人),该文件认为“编译器”是用于此类事情的好词。
ShreevatsaR

2
Javascript本身还是可以理解的,对吗?-不再有,它已由V8引擎即时编译为机器代码
Max Koretskyi

Answers:


91

您假定编译意味着获取源代码并生成机器代码,低级代码等。但是编译实际上只是意味着获取一个源代码并将其转换为另一个。因此,可以合理地说采用Typescript并生成JavaScript是一种编译形式。它与c#编译为IL语言时的行为(例如)没有什么不同。

就是说,我会说一个更好的词是Transpiling。我建议将Typescript编译器更好地描述为Transpiler。

区别是微妙的,可以将编译器视为编译器的一种。但是(纯)编译语言(通常)是将高级语言转换为低级(较近的机器代码)语言,例如C#示例。编译器将高级语言转换为相似级别(抽象)的语言(也是高级)。*

编译后的代码的结果通常不是您自己编写的语言。转译器的结果是另一种高级语言。从理论上讲,您可以编写IL(作为示例),但实际上它是由编译器生成的,并且没有工具或支持这样做的工具,您只能通过编译C#/ vb.net来生成IL。Javascript本身就是一种可用(和使用)的编程语言。

*很多警告,因为这些词的定义及其用法非常含糊


12
JavaScript是否严格低于TypeScript?
Bergi

3
尽管此答案中的所有内容都是正确且有用的,尤其是由于编译的定义始终是一个混乱的问题,所以它无法回答标题中的问题。该答案仅涉及TypeScript,而问题涉及Angular。区别是巨大的。甚至不知道TS是一回事就可以使用Angular。我很惊讶这个答案被接受。
Pedro A

3
编译器需要从本质上理解整个程序,才能生成另一个程序(该程序通常执行相同的操作,但是使用另一种语言-这包括机器代码)。
托尔比约恩Ravn的安徒生

8
我只读了两次,却在这里找不到问题的答案。答案就在下面。
kuncevic.dev

5
OP提出的隐式问题是为什么他们接受这一点,即“将Angular编译器称为编译器是否正确?” -这就是答案。所以我+1。另请参见人们说“翻译器”是什么意思?以及后续的“我的前十五个编译器”
ShreevatsaR

70

您似乎一口气问了三个问题:

  • 编译器和翻译器有什么区别?
  • Angular和TypeScript是否实现编译器或编译器?
  • 是否有单独的Angular编译器?它编译什么?

编译器和翻译器有什么区别?

@JörgWMittag对这个问题提供了很好的答案

Angular和TypeScript是否实现编译器或编译器?

TS和Angular都实现了真正的编译器。它们遵循与产生汇编代码的C / C ++编译器相同的词法分析,语法分析,语义分析和代码生成阶段(可能出于优化目的)。您可以看到AngularTS中的类/文件夹都被命名为“ compiler” 。

角度编译器与TypeScript编译器并没有真正的关系。这些是完全不同的编译器。

是否有单独的Angular编译器?它编译什么?

Angular有两个编译器:

  • 查看编译器
  • 模块编译器

视图编译器的工作是将您为组件模板指定的模板转换为组件的内部表示,该内部表示是视图工厂,然后用于实例化视图实例

除了将所述模板,视图编译器还编译在像装饰形式的各种元数据信息@HostBinding@ViewChild等等。

假设您这样定义一个组件及其模板:

@Component({
  selector: 'a-comp',
  template: '<span>A Component</span>'
})
class AComponent {}

编译器使用这些数据生成以下稍微简化的组件工厂:

function View_AComponent {
  return jit_viewDef1(0,[
      elementDef2(0,null,null,1,'span',...),
      jit_textDef3(null,['My name is ',...])
    ]

它描述了组件视图的结构,并在实例化组件时使用。第一个节点是元素定义,第二个节点是文本定义。您可以看到每个节点在通过参数列表实例化时都获得了所需的信息。解析所有必需的依赖项并在运行时提供它们是编译器的工作。

我强烈建议您阅读以下文章:

另外,请参见“ Angular AOT和JIT编译器之间的区别是什么”的答案

模块编译器的工作是创建一个模块工厂,该工厂基本上包含提供者的合并定义。

有关更多信息,请阅读:


1
@codepleb,请参阅Bergi的答案
Max Koretskyi

1
@codepleb请注意,GCC和许多其他编译器根本不会生成机器代码。实际上,GCC会自动调用系统来生成机器代码,但是它在没有外部帮助的情况下生成的代码仅仅是汇编,然后将其交给外部汇编器。
prosfilaes

7
@codepleb这个答案要好得多,实际上可以回答您的问题。还有时间重新考虑您的原始判断。
异步

3
@codepleb没有充分的理由使术语“翻译器”存在或曾经存在,它所做的只是误导。
Leushenko

2
@stom,对不起,这个问题太笼统了。最upvoted答案是相当不错的,虽然
马克斯Koretskyi

54

打字稿转成JS。然后是摇晃的树,“较少”(可选)以及进行部署的过程。但是,那样的东西(afaik)与“编译”没有任何关系。一切都捆绑在一起并进行了严格的优化,但是实际上并没有被编译,对吗?

编译是指将用语言A编写的程序转换为用语言B编写的语义上等效的程序,以便根据语言B的规则评估编译后的程序(例如,用B的解释程序对其进行解释)会产生相同的结果,并具有与根据语言A的规则评估原始程序具有相同的副作用(例如,使用A的解释器对其进行解释)。

汇编仅仅意味着一个程序翻译从语言语言。这就是全部。(还要注意,AB完全可能是同一语言。)

在某些情况下,对于某些类型的编译器,我们有更专门的名称,具体取决于AB以及编译器的作用:

  • 如果将A视为汇编语言而将B视为机器语言,则我们将其称为汇编器
  • 如果将A视为机器语言而将B视为汇编语言,则我们将其称为反汇编器
  • 如果A被认为比B低,那么我们称其为反编译器
  • 如果AB是相同的语言,并且生成的程序在某种程度上更快或更轻便,那么我们将其称为优化程序
  • 如果AB是相同的语言,并且生成的程序较小,那么我们将其称为minifier
  • 如果AB是相同的语言,并且生成的程序可读性较差,则我们将其称为混淆器
  • 如果AB被认为处于大致相同的抽象水平,则我们将其称为transpiler,并且
  • 如果认为AB处于大致相同的抽象级别,并且生成的程序保留了格式,注释和程序员的意图,从而有可能以与原始程序相同的方式来维护生成的程序,则我们称之为它是一种重新设计的工具

另外,请注意,较早的来源可能使用术语“翻译”和“翻译”,而不是“编译”和“编译器”。例如,C谈论“翻译单位”。

您也可能会偶然发现术语“语言处理器”。根据定义,这可能意味着编译器,解释器,或者意味着编译器和解释器。

JavaScript本身仍在解释,对吗?

JavaScript是一种语言。语言是一组逻辑规则和限制。语言不会被解释或编译。语言只是

编译和解释是编译器或解释器的特征(duh!)。每种语言都可以用编译器实现,每种语言都可以用解释器实现。许多语言同时具有编译器和解释器。许多现代的高性能执行引擎都具有至少一个编译器和至少一个解释器。

这两个术语属于不同的抽象层。如果英语是一种打字语言,则“解释语言”将是一种类型错误。

还要注意,某些语言既没有解释器也没有编译器。有些语言根本没有实现。它们仍然是语言,您可以用它们编写程序。您只是无法运行它们。

另外,请注意,所有内容都在某个时刻被解释:如果您想执行某件事,则必须对其进行解释。编译只是将代码从一种语言翻译成另一种语言。它不会运行。解释运行它。(有时,当解释器以硬件实现时,我们称其为“ CPU”,但它仍然是解释器。)

恰当的例子:当前存在的每个主流JavaScript实现都有一个编译器。

V8最初是一个纯粹的编译器:它直接将JavaScript编译为适当优化的本机代码。后来,添加了第二个编译器。现在,有两种编译器:轻量级编译器,可生成经过适当优化的代码,但编译器本身非常快,并且使用的RAM很少。该编译器还将配置文件代码注入已编译的代码中。第二个编译器是重量更重,运行更慢,更昂贵的编译器,但是生成的代码更紧密,更快。它还使用第一个编译器注入的性能分析代码的结果来做出动态优化决策。同样,基于该概要分析信息来决定使用第二个编译器重新编译哪些代码。请注意,任何时候都不会涉及口译员。V8从不解释,而是始终进行编译。它没有 甚至还包含口译员。(实际上,我相信现在确实如此,我正在描述前两个迭代。)

SpiderMonkey将JavaScript编译为SpiderMonkey字节码,然后对其进行解释。解释器还会分析代码,然后将最常执行的代码由编译器编译为本机代码。因此,SpiderMonkey包含两个编译器:一个从JavaScript到SpiderMonkey字节码,另一个从SpiderMonkey字节码到本机代码。

几乎所有的JavaScript执行引擎(V8除外)都遵循这种AOT编译器模型,该模型将JavaScript编译为字节码,并且使用混合模式引擎在解释和编译该字节码之间切换。

您在评论中写道:

我真的以为涉及机器代码。

“机器代码”甚至是什么意思?

一个人的机器语言是另一人的中间语言,反之亦然?例如,有些CPU可以本地执行JVM字节码,在这种CPU上,JVM字节码本地机器代码。并且有x86机器代码的解释器,当您运行这些x86机器代码时,解释为字节码。

有一个用Java编写的名为JPC的x86解释器。如果我在本机JVM CPU上运行的JPC上运行x86机器代码…这是字节码,哪个是本机代码?如果我将x86机器代码编译为JavaScript(是的,有工具可以做到)并在手机的浏览器(具有ARM CPU)中运行它,这是字节码又是本机代码?如果我正在编译的程序是SPARC仿真器,并且使用它来运行SPARC代码怎么办?

请注意,每种语言都会产生一台抽象机器,并且是该机器的机器语言。因此,每种语言(包括高级语言)都是本机代码。另外,您可以为每种语言编写翻译。因此,每种语言(包括x86机器代码)都不是母语。


4
+1代表对编译概念的深入解释,如果可以的话,+ 1代表这些要点。很有帮助。
Pedro A

1
虽然,我不得不说,从技术上讲,这并不能回答标题中的问题……不过,我还是值得的+1!
Pedro A

我同意它是隐式的,但是标题中的问题的答案是“所有OP列出的列表,不是编译就是什么角度编译”。
约尔格W¯¯米塔格

很好地解释了这实际上是关于命名约定而不是实质性区别的。也许可以通过提及微代码来改进-指出即使在机器代码级别,您也不是“最重要的” ...
AakashM

1
我以某种方式记得学习什么是编译器。如果那时有人告诉我,“编译器”是“代码翻译器”的同义词,那么获取它的用途或我们为什么需要它会容易得多。当然,从当今的角度来看,这听起来很荒谬,但这再次告诉我,只要有合适的人教给他一些东西,就能从中受益。谢谢。:)
codepleb

18

使您编写的代码在浏览器上运行涉及两件事:

1)将Typescript转换为JavaScript。这是一个已解决的问题。我认为他们只是使用webpack。

2)将角度抽象编译到JavaScript中。我的意思是诸如组件,管道,指令,模板等之类的东西。

如果您真的对第二个角度(角编译器)感兴趣,请观看编译器作者Tobias Bosch在AngularConnect 2016上解释Angular编译器

我认为在转译和编译之间存在一些混乱。这无关紧要,只是个人喜好,它们都只是代码表示之间的转换。但是我个人使用的定义是,在两种不同语言之间以类似的抽象级别(例如,打字稿转换为javascript)进行转译,而编译则需要将抽象级别降低。我认为从模板,组件,管道,指令等到javascript都是在抽象阶梯上走下坡路的原因,这就是为什么将其称为编译器。


1

角编译器

从Angular 4到5的最重要的变化之一是编译器的编写速度更快,更彻底。过去,Angular应用程序使用了我们所谓的即时(JIT)编译,即在运行时在浏览器中运行该应用程序之前对其进行编译。Angular 5中的编译器更新促进了向AOT的迁移,这使应用程序运行得更快,因为它在运行应用程序时执行较少的编译。从Angular CLI的1.5版本开始,在任何生产版本中默认都会启用AOT。

假设我们要构建一个用于部署的应用程序并运行以下命令:

ng build --prod

发生了一些事情:生产版本,缩小,捆绑资产,文件名哈希,摇树,AOT ...(我们可以使用标志启用/禁用此功能,例如aot = false)。简而言之,prod标志通过使用ngc(Angular编译器)进行AOT编译来创建应用程序的优化包,以创建适合浏览器的优化代码(是的,它会预编译模板)。

TypeScript编译器

TypeScript编译器tsc负责编译TypeScript文件。它是负责实现TypeScript功能(例如静态类型)的编译器,结果是纯JavaScript,其中删除了TypeScript关键字和表达式。

TypeScript编译器具有两个主要功能:它是一个编译器和一个类型检查器。编译器将TypeScript转换为JavaScript。它会对您的源代码进行以下转换:

  • 删除所有类型注释。
  • 为旧版本的JavaScript编译新的JavaScript功能。
  • 编译不是标准JavaScript的TypeScript功能。

调用它,编译器将搜索tsconfig.json中加载的配置(可在此处找到所有编译器选项的详细列表以及默认值)。

在大多数方面,TypeScript编译器的工作原理与任何编译器一样。但是有一个区别可以解决这个问题:默认情况下,即使遇到错误,编译器仍会继续发出JavaScript代码。幸运的是,可以通过noEmitOnError在tsconfig.json文件中将配置设置设置为true来禁用此行为。

需要注意的是tscngc具有不同的用途,而不是一个选择另一个。这个答案可能很有趣

这个答案是根据以下书籍的内容而精心设计的

  • Cloe,M.(2018年)。“ Angular 5项目:学习使用70多个项目构建单页Web应用程序”。

  • 杜威,B。格罗斯尼克劳斯,K。贾比克瑟(2017)。“使用Visual Studio 2017构建Web应用程序:使用.NET Core和现代JavaScript框架”。

  • Freeman,A.(2019年)。“基本TypeScript:从初学者到专业人士”。

  • Ghiya,P.(2018年)。“ TypeScript微服务”。

  • Iskandar,A.,Chivukulu,S.(2019年)。“使用Angular和Bootstrap进行Web开发-第三版”。

  • Hennessy,K.,Arora,C.(2018年)。“示例角度6”。

  • Jansen,R.,Wolf,I.,Vane,V.(2016年)。“ TypeScript:现代JavaScript开发”。

  • Mohammed,Z.(2019年)。“角度项目”。

  • Seshadri,S.(2018年)。“角度:启动并运行”。

  • Wilken,J.(2018年)。“行动中的角度”。

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.