Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 66 题:ES6 代码转成 ES5 代码的实现思路是什么 #112

Open
zeroone001 opened this issue May 5, 2019 · 11 comments
Open

第 66 题:ES6 代码转成 ES5 代码的实现思路是什么 #112

zeroone001 opened this issue May 5, 2019 · 11 comments
Labels

Comments

@zeroone001
Copy link

No description provided.

@Gentlemancj
Copy link

将ES6的代码转换为AST语法树,然后再将ES6 AST转为ES5 AST,再将AST转为代码

@wingmeng
Copy link

wingmeng commented May 5, 2019

题目说的是 ES6,所以不考虑 .jsx.ts 这类 js 拓展语言。
ES6 转 ES5 目前行业标配是用 Babel,转换的大致流程如下:

  1. 解析:解析代码字符串,生成 AST;
  2. 转换:按一定的规则转换、修改 AST;
  3. 生成:将修改后的 AST 转换成普通代码。

如果不用工具,纯人工的话,就是使用或自己写各种 polyfill 了。

@FishPlusOrange
Copy link

把 ES6 代码转成 ES5 代码的实现思路可以分成三步:

  • 打开冰箱
  • 把大象装进去
  • 关上冰箱

喔,不对,原谅我开了个玩笑,嗯,有点冷……

回到正题上来,说到 ES6 代码转成 ES5 代码,我们肯定会想到 Babel。所以,我们可以参考 Babel 的实现方式。

那么 Babel 是如何把 ES6 转成 ES5 呢,其大致分为三步:

  • 将代码字符串解析成抽象语法树,即所谓的 AST
  • 对 AST 进行处理,在这个阶段可以对 ES6 代码进行相应转换,即转成 ES5 代码
  • 根据处理后的 AST 再生成代码字符串

基于此,其实我们自己就可以实现一个简单的“编译器”,用于把 ES6 代码转成 ES5。

比如,可以使用 @babel/parserparse 方法,将代码字符串解析成 AST;使用 @babel/coretransformFromAstSync 方法,对 AST 进行处理,将其转成 ES5 并生成相应的代码字符串;过程中,可能还需要使用 @babel/traverse 来获取依赖文件等。对此感兴趣的可以看看这个

如果有误,希望可以帮忙指出来,多谢。

@georgehpj
Copy link

说说我的理解哦
es6比es5多出来的部分分两类
一类是语法,如箭头函数,解构;
一类是新的类、新的类方法、新的实例方法,如:Promise, Array.from, Array.prototype.find

babel在做语法转换的时候,通过抽象语法树来实现代码层面的翻译。
比如将
const fn = () => {
Array.isArray([1, 2, 3]);
};
转成
"use strict";
var fn = function fn() {
Array.isArray([1, 2, 3]);
};

对于新的类、类方法,实例方法,基本就是polyfill,或者polyfill加上代码转换。
拿Array.from来说,只需要使用es5的语法,自己实现一遍Array.from,就可以用不改动源代码而使用Array.from这个es6的api了,@babel/polyfill这个包就是做这事儿的。
复杂点的Promise在babel转译的时候,不仅会调整源代码,还需要引入@babel/polyfill。有时候会遇到regeneratorRuntime is not defined这个报错,原因是源代码中Promise部分被转译了,转译后用到的regeneratorRuntime在@babel/polyfill中,但@babel/polyfill没被引入。

@habc0807
Copy link

ES6 代码转换成 ES5 的思路大家都讲的差不多,我来做个补充。

Babel 将把 ES6 转成 ES5 第二步,从 Babel 6.0 开始,就不再对代码进行转换。现在 Babel 只负责parse 和 generate 流程,也就是专注于解析和生成阶段。转换代码的 transform 过程全都交给bable插件去做了。

我们的项目里的 .babelrc 文件就是用来配置babel处理的,常有plugins 与 presets配置项,当他们同时存在的时候,先执行plugins从上到下,在执行presets从左到右。

@superermiao
Copy link

借用babel转换思想,将es6解析成AST,然后按照统一规则转换修改AST,再将AST解析成es5

@chaijinsong
Copy link

涉及到的主要是AST相关的内容,AST(Abstract Syntax Tree)中文叫抽象语法树,是用来表示源代码语法的一种树形结构,树上的每个节点都代表源代码的一种结构。AST在我们日常应用中非常广泛,我们的代码高亮,代码检查等都是依靠的AST。

那么ES6转ES5的思路,其实就是在处理AST的过程中进行操作。转化代码的流程一般分为三步

  1. 将代码通过解释器转化为AST,可以通过 astexplorer 来查看代码对应的AST结构
  2. 通过一定的规则,去修改AST的结构(常见的比如转jsx,ES6转ES5都是在这一步进行操作)
  3. 将修改后的AST转化为普通代码

现在一般使用的就是bable转ES6,具体的ES6转ES5在第二步中的逻辑,那就得看bable中转ES6的babel-preset-es2015 对AST进行操作的源码了

@zhishaofei3
Copy link

这问的是问题么?
你说的是普通开发者的思路?
还是babel作者的思路啊??

@JohnieXu
Copy link

JohnieXu commented Sep 29, 2019

ES6转ES5分为以下两种情况
1.语法转换
ES6语法通过babel等工具为ES5语法,本质是将ES6语法转AST(抽象语法数——对编程语言编写的程序的一种描述)再将AST转为ES5语法代码;例如:let,const转换为var,箭头函数转换为function函数声明等
2.API转换
采用babel-polyfill等工具对ES5中不存在的API(包括Set等ES6中新的数据结构)做修复,例如:Array.prototype.includes Set Map等在ES5中不存在,需要用相应的ES5代码实现这些API


补充说明

  • .vue文件通过webpack的vue-loader分析出script style template 再走上面的ES6转ES5流程
  • jsx通过babel插件转js语法再走ES6转ES5
  • ts通过tsc结合tsconfig.json直接转ES5

@soraly
Copy link

soraly commented Jun 29, 2020

ES6 代码转成 ES5 代码的实现思路是什么

  • 把代码字符串解析成AST(抽象语法树)
  • AST就是一个json,按照一定规则把这个json里ES6部分的东西转换成ES5的
  • 再把修改后的AST转换成代码

关于AST

AST的全称是abstract syntax tree,中文名叫抽象语法树,假设有一个函数,

function hello(a, b, c){ 
}

这段代码被解析成的ast树就是

type: Program
-
body
-
#1
type: FunctionDeclaration
-
id
type: Identifier
name: hello
-
params
-
#1
type: Identifier
name: a
-
#2
type: Identifier
name: b
-
#3
type: Identifier
name: c
-
body
type: BlockStatement
body
generator: false
expression: false
async: false
sourceType: script

这样看起来还不是很直观,其实上面的树就等于

{
  "type": "Program",
  "body": [
    {
      "type": "FunctionDeclaration",
      "id": {
        "type": "Identifier",
        "name": "hello"
      },
      "params": [
        {
          "type": "Identifier",
          "name": "a"
        },
        {
          "type": "Identifier",
          "name": "b"
        },
        {
          "type": "Identifier",
          "name": "c"
        }
      ],
      "body": {
        "type": "BlockStatement",
        "body": []
      },
      "generator": false,
      "expression": false,
      "async": false
    }
  ],
  "sourceType": "script"
}

有了这个json后,就可以对代码进行操作了。在没有树的情况下,如果要对文件里的某一个语句进行替换的话,一般就是全局
搜索然后replace,这样有可能影响到别的代码,但是有了树后,就可以对这个json进行操作,精确地去修改某个对象的属性,也就不会影响到别的代码了。所以babel转换ES6的核心,就是在ast中按照一定的规则取修改json里的属性和方法,然后再把tree转换成代码

@Yangfan2016
Copy link

使用babel

  1. es6 代码字符串解析生成 AST
  2. 按照es5 的规则 转换 生成符合es5规范的 AST
  3. 将 AST 转换为代码字符串

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests