我今天被问到,无法给出正确的答案。
Typescript 转译为 JS。然后是摇树,“更少”(可选)以及在进行部署过程中的其他内容。但是这样的事情(afaik)与“编译”没有任何关系。一切都被捆绑并进行了高度优化,但实际上并没有编译,对吧?
甚至还有一个“提前”编译器,它确实做了一个引人注目的工作。我想念什么?
Javascript 本身仍然被解释,对吧?
我今天被问到,无法给出正确的答案。
Typescript 转译为 JS。然后是摇树,“更少”(可选)以及在进行部署过程中的其他内容。但是这样的事情(afaik)与“编译”没有任何关系。一切都被捆绑并进行了高度优化,但实际上并没有编译,对吧?
甚至还有一个“提前”编译器,它确实做了一个引人注目的工作。我想念什么?
Javascript 本身仍然被解释,对吧?
您假设编译意味着获取源代码并生成机器代码、低级代码等。但编译实际上只是意味着获取一个源代码并将其转换为另一个源代码。所以说使用 Typescript 并生成 JavaScript 是一种编译形式似乎是合理的。它与(例如)c# 在编译成 IL 语言时所做的并没有什么不同。
也就是说,我会说一个更好的词是Transpiling。我建议将 Typescript 编译器更好地描述为 Transpiler。
区别是微妙的,转译器可以被认为是一种编译器。但是(纯)编译语言(通常)将高级语言转换为低级语言(更接近机器代码),例如 C# 示例。转译器将高级语言转换为类似级别(抽象)语言(也是高级)。*
编译代码的结果通常不是您自己编写的语言。转译器的结果是另一种高级语言。理论上,您可以编写 IL(作为示例),但它实际上是设计为由编译器生成的,并且没有工具或支持这样做,您只能通过编译 C#/vb.net 来生成 IL。而 Javascript 本身就是一种可用(和使用)的编程语言。
*很多警告,因为这些词的定义及其用法非常模糊
您似乎在一个问题中提出三个问题:
编译器和转译器有什么区别?
@JörgWMittag为这个问题提供了一个很好的答案。
Angular 和 TypeScript 是否实现编译器或转译器?
TS 和 Angular 都实现了真正的编译器。它们遵循与生成汇编代码的 C/C++ 编译器相同的词法分析、解析、语义分析和代码生成阶段(可能用于优化除外)。您可以看到类/文件夹在Angular和TS中都被命名为“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 编译器有什么区别的答案。
模块编译器的工作是创建一个模块工厂,它基本上包含提供者的合并定义。
有关更多信息,请阅读:
Typescript 转换为 JS。然后是摇树,“更少”(可选)以及在进行部署过程中的其他内容。但是这样的事情(afaik)与“编译”没有任何关系。一切都被捆绑并进行了高度优化,但实际上并没有编译,对吧?
编译意味着将用语言A编写的程序转换为用语言B编写的语义等价程序,以便根据语言B的规则评估编译的程序(例如用B的解释器解释它)产生相同的结果并具有与根据语言A的规则评估原始程序的副作用相同(例如,使用A的解释器对其进行解释)。
编译只是意味着将程序从语言A翻译成语言B。这就是它的全部含义。(另请注意,A和B完全有可能是同一种语言。)
在某些情况下,我们对某些类型的编译器有更专业的名称,这取决于A和B是什么,以及编译器的作用:
另外,请注意,较旧的来源可能使用术语“翻译”和“翻译器”而不是“编译”和“编译器”。例如,C 谈到“翻译单元”。
您可能还会偶然发现“语言处理器”一词。这可能意味着编译器、解释器或编译器和解释器,具体取决于定义。
Javascript 本身仍然被解释,对吧?
JavaScript 是一种语言。语言是一组逻辑规则和限制。语言不被解释或编译。语言只是。
编译和解释是编译器或解释器的特征(呃!)。每种语言都可以用编译器实现,每种语言都可以用解释器实现。许多语言都有编译器和解释器。许多现代高性能执行引擎都具有至少一个编译器和至少一个解释器。
这两个术语属于不同的抽象层。如果英语是一种类型化语言,“interpreted-language”将是类型错误。
另请注意,某些语言既没有解释器也没有编译器。有些语言根本没有实现。不过,它们是语言,你可以用它们编写程序。你只是无法运行它们。
另外,请注意,一切都在某个时候被解释:如果你想执行某些东西,你必须解释它。编译只是将代码从一种语言翻译成另一种语言。它不运行它。解释运行它。(有时,当解释器在硬件中实现时,我们称其为“CPU”,但它仍然是解释器。)
恰当的例子:当前存在的每一个主流 JavaScript 实现都有一个编译器。
V8 最初是一个纯编译器:它将 JavaScript 直接编译为经过适度优化的本机机器代码。后来,添加了第二个编译器。现在,有两个编译器:一个轻量级编译器,它生成适度优化的代码,但编译器本身非常快并且使用很少的 RAM。该编译器还将分析代码注入到已编译的代码中。第二个编译器是一个更重量级、更慢、更昂贵的编译器,然而,它产生的代码更紧凑、更快。它还使用第一个编译器注入的分析代码的结果来做出动态优化决策。此外,使用第二个编译器重新编译哪些代码是基于该分析信息做出的。请注意,任何时候都不会涉及口译员。V8 从不解释,它总是编译。它没有 t 甚至包含解释器。(实际上,我相信现在确实如此,我正在描述前两次迭代。)
SpiderMonkey 将 JavaScript 编译为 SpiderMonkey 字节码,然后对其进行解释。解释器还分析代码,然后最常执行的代码由编译器编译为本机机器代码。因此,SpiderMonkey 包含两个编译器:一个从 JavaScript 到 SpiderMonkey 字节码,另一个从 SpiderMonkey 字节码到本地机器码。
几乎所有 JavaScript 执行引擎(V8 除外)都遵循这种将 JavaScript 编译为字节码的 AOT 编译器模型,以及在解释和编译该字节码之间切换的混合模式引擎。
你在评论中写道:
我真的在想机器代码涉及到某个地方。
“机器码”到底是什么意思?
什么是一个人的机器语言是另一个人的中间语言,反之亦然?例如,有些 CPU 可以本地执行 JVM 字节码,在这样的 CPU 上,JVM 字节码是本地机器码。并且有 x86 机器码的解释器,当您运行这些 x86 机器码时,它们会被解释为字节码。
有一个用 Java 编写的称为 JPC 的 x86 解释器。如果我在本机 JVM CPU 上运行的 JPC 上运行 x86 机器代码……哪个是字节码,哪个是本机代码?如果我将 x86 机器代码编译为 JavaScript(是的,有可以做到这一点的工具)并在我的手机(具有 ARM CPU)上的浏览器中运行它,哪个是字节码,哪个是本机机器代码?如果我正在编译的程序是一个 SPARC 仿真器,我用它来运行 SPARC 代码怎么办?
请注意,每种语言都衍生出一个抽象机器,并且是该机器的机器语言。因此,每种语言(包括非常高级的语言)都是本机机器代码。此外,您可以为每种语言编写解释器。因此,每种语言(包括 x86 机器代码)都不是本地语言。
让您编写的代码在浏览器上运行涉及两件事:
1) 将Typescript 转译成 JavaScript。这是一个已解决的问题。我认为他们只是使用 webpack。
2)将角度抽象编译成 JavaScript。我的意思是组件、管道、指令、模板等。这就是 Angular 核心团队的工作。
如果您真的对第二点感兴趣,角度编译器,请观看编译器作者 Tobias Bosch 在 AngularConnect 2016 上解释 Angular 编译器。
我认为在转译和编译之间存在一些混淆。这有点无关紧要,是个人品味的问题,它们都只是代码表示之间的转换。但我个人使用的定义是,在两种不同语言之间进行类似抽象级别的转换(例如从 typescript 到 javascript),而编译则需要降低抽象级别。我认为从模板、组件、管道、指令等到只是 javascript 是抽象阶梯的下一个步骤,这就是它被称为编译器的原因。
从 Angular 4 到 5 最重要的变化之一是编译器被重写得更快、更彻底。过去,Angular 应用程序使用我们所谓的即时 (JIT) 编译,其中应用程序在运行之前在浏览器中编译。Angular 5 中的编译器更新推进了向 AOT 的迁移,这使得应用程序运行得更快,因为它在运行应用程序时执行的编译更少。自 Angular CLI 1.5 版本以来,任何生产版本都默认启用 AOT。
假设我们要构建一个用于部署的应用程序并运行以下命令:
ng build --prod
发生了一些事情:生产版本、缩小、捆绑资产、文件名哈希、摇树、AOT ...(我们可以使用标志启用/禁用它,例如 aot=false)。简而言之,prod 标志通过使用ngc(Angular 编译器)进行 AOT 编译来创建应用程序的优化包,以创建可供浏览器使用的优化代码(是的,它预编译模板)。
TypeScript 编译器tsc负责编译 TypeScript 文件。编译器负责实现 TypeScript 功能,例如静态类型,结果是纯 JavaScript,其中 TypeScript 关键字和表达式已被删除。
TypeScript 编译器有两个主要特性:它是一个转译器和一个类型检查器。编译器将 TypeScript 转换为 JavaScript。它对您的源代码进行以下转换:
调用它时,编译器会搜索 tsconfig.json 中加载的配置(所有编译器选项的详细列表以及默认值可以在此处找到)。
在大多数方面,TypeScript 编译器的工作方式与任何编译器一样。但是有一个区别可以让粗心大意的人发现:默认情况下,即使遇到错误,编译器也会继续发出 JavaScript 代码。noEmitOnError
幸运的是,可以通过在 tsconfig.json 文件中将配置设置设置为 true 来禁用此行为。
注意:tsc和ngc有不同的目的,而不是选择一个。这个答案可能很有趣。
这个答案是根据以下书籍的内容制作的
克洛,M.(2018)。“Angular 5 项目:学习使用 70 多个项目构建单页 Web 应用程序”。
Dewey, B.、Grossnicklaus, K.、Japikse, P. (2017)。“使用 Visual Studio 2017 构建 Web 应用程序:使用 .NET Core 和现代 JavaScript 框架”。
弗里曼,A.(2019)。“基本 TypeScript:从初学者到专业人士”。
Ghiya, P. (2018)。“TypeScript 微服务”。
Iskandar, A., Chivukulu, S. (2019)。“使用 Angular 和 Bootstrap 进行 Web 开发 - 第三版”。
Hennessy, K., Arora, C. (2018)。“示例 Angular 6”。
Jansen, R., Wolf, I., Vane, V. (2016)。“TypeScript:现代 JavaScript 开发”。
穆罕默德,Z.(2019)。“角项目”。
Seshadri, S. (2018)。“角度:启动并运行”。
威尔肯,J. (2018)。“角在行动”。