角度编译器"编译"了什么?

cod*_*leb 82 javascript typescript angular-cli angular-compiler-cli angular

我今天被问到,并没有给出正确的答案.

打字稿转化为JS.然后是树摇动,"少"(可选)以及在进行部署的过程中还有什么.但是那些(afaik)与"编译"无关.一切都被捆绑并大量优化,但它实际上并没有编译,对吧?

甚至有一个提前编译器,它确实做了明显的工作.我错过了什么?

Javascript本身仍然是解释的,对吧?

Lia*_*iam 88

您假设编译意味着获取源代码并生成机器代码,低级代码等.但实际上编译只意味着获取一个源代码并将其转换为另一个源代码.所以说使用Typescript和生成JavaScript是一种编译形式似乎是合理的.它与编译成IL语言时c#的作用并没有什么不同.

那就是说,我要说的更好的话是Transpiling.我建议将Typescript编译器更好地描述为一个Transpiler.

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

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

*由于这些词语的定义及其用法非常模糊,因此需要注意很多

  • JavaScript不是严格低于TypeScript的级别吗? (12认同)
  • 我刚读了两遍,但在这里找不到问题的答案.答案就在下面. (8认同)
  • OP提出的隐含问题,即他们接受这个问题的原因是"将Angular编译器称为编译器是否正确?" - 这就是答案的答案.所以来自我的+1.另见[当人们说"transpiler"时人们的意思是什么?](http://composition.al/blog/2017/07/30/what-do-people-mean-when-they-say-transpiler/)后续["我的前十五个编译器"](http://composition.al/blog/2017/07/31/my-first-fifteen-compilers/). (5认同)
  • 编译器需要基本上理解整个程序才能生成另一个程序(通常用另一种语言做同样的事情 - 这包括机器代码). (3认同)
  • 虽然这个答案中的所有内容都是正确和有用的,特别是因为编译的定义始终是一个混乱的问题,但它并没有回答标题中的问题.这个答案仅涉及TypeScript,而问题是关于Angular.差异很大.完全可以使用Angular,甚至不知道TS是一个东西.我很惊讶这个答案被接受了. (2认同)
  • "透明"从来都不是一个有用的词.它唯一能实现的是导致像OP中那样的误解.不惜一切代价避免并正确地引用这些东西:作为**编译器**. (2认同)

Max*_*kyi 67

你似乎在一个问三个问题:

  • 编译器和转换器之间有什么区别?
  • 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 {}
Run Code Online (Sandbox Code Playgroud)

使用此数据,编译器生成以下略微简化的组件工厂:

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

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

我强烈建议阅读这些文章:

另外,请参阅Angular AOT和JIT编译器之间的区别答案.

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

有关更多信息,请阅读:

  • @codepleb这个答案远非优越,实际上回答了你的问题.还有时间重新考虑你原来的判断. (6认同)
  • @codepleb没有充分理由将"transpiler"这个词存在或者永远存在,它所做的只是误导. (3认同)
  • @stom,对不起,这个问题太宽泛了.最受欢迎的答案是相当不错的 (2认同)

Jör*_*tag 51

打字稿到JS.然后是树摇动,"少"(可选)以及在进行部署的过程中还有什么.但是那些(afaik)与"编译"无关.一切都被捆绑并大量优化,但它实际上并没有编译,对吧?

编译意味着将用语言A编写的程序转换为用语言B编写的语义上等效的程序,以便根据语言B的规则评估编译的程序(例如用B的解释器解释它)产生相同的结果并具有与根据语言A的规则评估原始程序相同的副作用(例如,用A的解释器解释它).

汇编仅仅意味着一个程序翻译从语言语言.这就是它的意思.(另请注意,AB完全可以使用相同的语言.)

在某些情况下,我们为某些类型的编译器提供了更多专用名称,具体取决于AB是什么,以及编译器的作用:

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

另请注意,较旧的来源可能使用术语"翻译"和"翻译"而不是"编译"和"编译器".例如,C谈到"翻译单位".

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

Javascript本身仍然被解释,对吧?

JavaScript是一种语言.语言是一组逻辑规则和限制.不解释或编译语言.语言就是这样.

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

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

另请注意,某些语言既没有解释器也没有编译器.有些语言根本没有实现.它们仍然是语言,您可以在其中编写程序.你无法运行它们.

另外,请注意在某些时候解释所有内容:如果要执行某些操作,则必须对其进行解释.编译只是将代码从一种语言翻译成另一种语言.它没有运行它.解释运行它.(有时,当解释器在硬件中实现时,我们称之为"CPU",但它仍然是一个解释器.)

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

V8最初只是一个纯粹的编译器:它直接编译JavaScript到适度优化的本地机器代码.后来又添加了第二个编译器.现在,有两个编译器:一个轻量级编译器,可以产生适度优化的代码,但编译器本身非常快并且使用很少的RAM.此编译器还将分析代码注入已编译的代码中.第二个编译器是一个更重量级,更慢,更昂贵的编译器,然而,它产生更严格,更快的代码.它还使用第一个编译器注入的分析代码的结果来做出动态优化决策.此外,基于该分析信息决定使用第二编译器重新编译哪个代码.请注意,任何时候都不涉及翻译.V8永远不会解释,它总是编译.它甚至不包含翻译.(实际上,我相信现在它确实如此,我正在描述前两次迭代.)

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

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

你在评论中写道:

我真的以为机器代码涉及到某个地方.

"机器代码"甚至意味着什么?

一个人的机器语言是另一个人的中间语言,反之亦然?例如,有一些CPU本身可以执行JVM字节码,在这样的CPU上,JVM字节码本地机器代码.而且有口译x86机器代码,当您运行的那些x86机器代码解释字节码.

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

请注意,每种语言都会引发抽象机器,并且是该机器的机器语言.因此,每种语言(包括非常高级的语言)都是本机机器代码.此外,您可以为每种语言编写解释器.因此,每种语言(包括x86机器代码)都不是原生的.

  • +1对编译概念的深入解释,如果可以的话,那些子弹点的另外+1.很有帮助. (4认同)

Nat*_*per 17

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

1)将Typescript显示为JavaScript.这是一个解决的问题.我认为他们只是使用webpack.

2)将角度抽象编译成JavaScript.我的意思是组件,管道,指令,模板等.这是角度核心团队的工作.

如果您真的对第二位感兴趣,那么角度编译器,监视编译器作者Tobias Bosch将在AngularConnect 2016上解释Angular Compiler.

我认为在转换和编译之间会有一些混乱.它有点无关紧要,是个人品味的问题,它们都只是代码表示之间的转换.但是,定义,我个人用的是transpilation是两种不同语言之间的相似的抽象级别(例如,打字稿的JavaScript),而编译需要一个步骤,抽象程度下降.我认为从模板,组件,管道,指令等只是javascript是抽象阶梯的一步,这就是为什么它被称为编译器.