前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >babel操作AST

babel操作AST

原创
作者头像
挥刀北上
修改于 2021-02-19 09:56:59
修改于 2021-02-19 09:56:59
1.6K03
代码可运行
举报
文章被收录于专栏:Node.js开发Node.js开发
运行总次数:3
代码可运行

前一篇文章讲解了什么是AST,但是没有说明如何操作AST,下面来讲解下如何使用babel来操作AST,首先看一下流程图:

操作AST流程图
操作AST流程图

babel操作AST的流程如上图,首先将js代码转化为AST语法树,然后利用一些特定的库去修改AST语法树,然后得到新的语法树,将新的语法树转化为js代码,这样就可以转化js代码了。

需要操作 AST 代码,这里,我们需要借助两个库,分别是 @babel/core 和 babel-types。 其中 @babel/core 是 babel 的核心库,用来实现核心转换引擎,babel-types 类型判断,用于生成AST零部件。通过 npm i @babel/core babel-types -D 安装依赖

我们用一个例子来说明babel的使用方法,首先源代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const sum=(a,b)=>a+b;

转化后的代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const sum = function(a,b){
    return a+b;
}

本质就是讲箭头函数转化为function函数。

利用这个网站来分析下两端代码的AST有什么不同:

第一段代码的AST:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 源代码的 AST
{
    "type": "Program",
    "start": 0,
    "end": 21,
    "body": [
        {
            "type": "VariableDeclaration",
            "start": 0,
            "end": 21,
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "start": 6,
                    "end": 20,
                    "id": {
                        "type": "Identifier",
                        "start": 6,
                        "end": 9,
                        "name": "sum"
                    },
                    "init": {
                        "type": "ArrowFunctionExpression",
                        "start": 10,
                        "end": 20,
                        "id": null,
                        "expression": true,
                        "generator": false,
                        "async": false,
                        "params": [
                            {
                                "type": "Identifier",
                                "start": 11,
                                "end": 12,
                                "name": "a"
                            },
                            {
                                "type": "Identifier",
                                "start": 13,
                                "end": 14,
                                "name": "b"
                            }
                        ],
                        "body": {
                            "type": "BinaryExpression",
                            "start": 17,
                            "end": 20,
                            "left": {
                                "type": "Identifier",
                                "start": 17,
                                "end": 18,
                                "name": "a"
                            },
                            "operator": "+",
                            "right": {
                                "type": "Identifier",
                                "start": 19,
                                "end": 20,
                                "name": "b"
                            }
                        }
                    }
                }
            ],
            "kind": "const"
        }
    ],
    "sourceType": "module"
}

第二段代码的AST:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 目标代码的 `AST`
{
    "type": "Program",
    "start": 0,
    "end": 48,
    "body": [
        {
            "type": "VariableDeclaration",
            "start": 0,
            "end": 48,
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "start": 6,
                    "end": 47,
                    "id": {
                        "type": "Identifier",
                        "start": 6,
                        "end": 9,
                        "name": "sum"
                    },
                    "init": {
                        "type": "FunctionExpression",
                        "start": 12,
                        "end": 47,
                        "id": null,
                        "expression": false,
                        "generator": false,
                        "async": false,
                        "params": [
                            {
                                "type": "Identifier",
                                "start": 22,
                                "end": 23,
                                "name": "a"
                            },
                            {
                                "type": "Identifier",
                                "start": 25,
                                "end": 26,
                                "name": "b"
                            }
                        ],
                        "body": {
                            "type": "BlockStatement",
                            "start": 28,
                            "end": 47,
                            "body": [
                                {
                                    "type": "ReturnStatement",
                                    "start": 32,
                                    "end": 45,
                                    "argument": {
                                        "type": "BinaryExpression",
                                        "start": 39,
                                        "end": 44,
                                        "left": {
                                            "type": "Identifier",
                                            "start": 39,
                                            "end": 40,
                                            "name": "a"
                                        },
                                        "operator": "+",
                                        "right": {
                                            "type": "Identifier",
                                            "start": 43,
                                            "end": 44,
                                            "name": "b"
                                        }
                                    }
                                }
                            ]
                        }
                    }
                }
            ],
            "kind": "const"
        }
    ],
    "sourceType": "module"
}

仔细对比发现,我们发现主要不同就在于 init 这一段,一个是 ArrowFunctionExpression , 另一个是 FunctionExpression , 我们只需要将 ArrowFunctionExpression 下的内容改造成跟 FunctionExpression 即可。我们在修改第一段代码的AST时着重修改这里,如何修改呢?看代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//babel 核心库,用来实现核心转换引擎
const babel = require('@babel/core')
//类型判断,生成AST零部件
const types = require('babel-types')

//源代码
const code = `const sum=(a,b)=>a+b;` //目标代码 const sum = function(a,b){ return a + b }

这里我们需要用到 babel 中的 transform 方法,它可以将 js 代码转换成 AST ,过程中可以通过使用 plugins 对 AST 进行改造,最终生成新的 AST 和 js 代码,其整个过程用网上一个比较贴切的图就是:

我们需要使用babel的transform方法,使用方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//transform方法转换code
//babel先将代码转换成ast,然后进行遍历,最后输出code

let result = babel.transform(code,{
    plugins:[
        {
            visitor
        }
    ]
})

transform的第一个参数为code也就是源代码,第二个参数为一个对象,对象的属性有plugins和preset两个属性,这里我们只用plugins,plugins是一个数组,数组的每一项是一个对象,对象的属性为visiter

它是一个插件对象,可以对特定类型的节点进行处理,这里我们需要处理的节点是ArrowFunctionExpression,它常见的配置方式有两种: 一种是单一处理,结构如下,其中 path 代表当前遍历的路径 path.node 代表当前变量的节点

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let visitor = {
    ArrowFunctionExpression(path){
    
    }
}

另一种是用于输入和输出双向处理,结构如下,参数 node 表示当前遍历的节点

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let visitor = {
     ArrowFunctionExpression : {
        enter(node){
            
        },
        leave(node){
            
        }
    }
}

这里我们使用第一种:

通过分析目标代码的 AST,我们发现,需要一个 FunctionExpression , 这时候我们就需要用到 babel-types ,它的作用就是帮助我们生产这些节点 我们通过其 npm 包的文档查看,构建一个 FunctionExpression 需要的参数如下:

参照 AST 我们可以看到其 id 为 null,params 是原 ArrowFunctionExpression 中的 params,body 是一个blockStatement,我们也可以通过查看 babel-types 文档,用 t.blockStatement(body, directives) 来创建,依次类推,照猫画虎,最终得到的结果如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //原 params
    let params = path.node.params;
    //创建一个blockStatement
    let blockStatement = types.blockStatement([
        types.returnStatement(types.binaryExpression(
            '+',
            types.identifier('a'),
            types.identifier('b')
        ))
    ]);
    //创建一个函数
    let func = types.functionExpression(null, params, blockStatement, false, false);

然后通过path.replaceWith(func); 将其替换即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//babel 核心库,用来实现核心转换引擎
const babel = require('@babel/core')
//类型判断,生成AST零部件
const types = require('babel-types')

//源代码
const code = `const sum=(a,b)=>a+b;` //目标代码 const sum = function(a,b){ return a + b }

//插件对象,可以对特定类型的节点进行处理
let visitor = {
    //代表处理 ArrowFunctionExpression 节点
    ArrowFunctionExpression(path){
        let params = path.node.params;
        //创建一个blockStatement
        let blockStatement = types.blockStatement([
            types.returnStatement(types.binaryExpression(
                '+',
                types.identifier('a'),
                types.identifier('b')
            ))
        ]);
        //创建一个函数
        let func = types.functionExpression(null, params, blockStatement, false, false);
        //替换
        path.replaceWith(func);
    }
}

//transform方法转换code
//babel先将代码转换成ast,然后进行遍历,最后输出code
let result = babel.transform(code,{
    plugins:[
        {
            visitor
        }
    ]
})

console.log(result.code);

以上便是利用bebel来操作AST的操作,希望对你有所帮助。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Babel原理
Babel是什么?我们为什么要了解它? 1. 什么是babel ? Babel 是一个 JavaScript 编译器。他把最新版的javascript编译成当下可以执行的版本,简言之,利用babel就
null仔
2020/02/28
1.2K0
Babel原理
一文助你搞懂 AST
抽象语法树(Abstract Syntax Tree)简称 AST,是源代码的抽象语法结构的树状表现形式。webpack、eslint 等很多工具库的核心都是通过抽象语法书这个概念来实现对代码的检查、分析等操作。今天我为大家分享一下 JavaScript 这类解释型语言的抽象语法树的概念
coder_koala
2020/06/22
2.7K1
使用 AST 实现 babel 插件编写
抽象语法树 (Abstract Syntax Tree) 是源代码语法结构的⼀种抽象表示,以树状描述编程语⾔的语法结构,每个节点表示源代码中的⼀种结构。AST常用于代码语法检查、⻛格检查、格式化、代码提示、混淆压缩、自动补全等,还可以用来优化代码结构,如 webpack 以及 CommonJS、AMD、CMD、UMD等代码规范之间的转化等。
CS逍遥剑仙
2022/08/01
1.3K0
假如面试官问你Babel的原理该怎么回答
简单地说,Babel 能够转译 ECMAScript 2015+ 的代码,使它在旧的浏览器或者环境中也能够运行。
loveX001
2022/10/10
2970
掌握 AST,轻松落地关键业务「技术创作101训练营」
如果你查看目前任何主流的项目中的 devDependencies,我们不会在生产环境用到,但是它们在开发过程中充当着重要的角色。归纳一下有:javascript转译、代码压缩、css预处理器、elint、pretiier,postcss等。所有的上述工具,不管怎样,都建立在了AST这个巨人的肩膀上,都是 AST 的运用:
奋飛
2020/09/20
1.1K0
掌握 AST,轻松落地关键业务「技术创作101训练营」
编译原理工程实践—05使用babel操作AST实现代码转换
babel 是一个 JavaScript 编译器,使用 babel 可以随心所欲地转化和操作 AST,实现对代码的分析、优化、变更等。可以在 https://esprima.org/demo/parse.html 体验转换查看 js 代码的词法、语法和AST。
CS逍遥剑仙
2025/05/12
710
手把手带你走进Babel的编译世界
谈及 Babel,必然离不开 AST。有关 AST 这个知识点其实是很重要的,但由于涉及到代码编译阶段,大多情况都是由各个框架内置相关处理,所以作为开发(使用)者本身,往往会忽视这个过程。希望通过这篇文章,带各位同学走进 AST,借助 AST 发挥更多的想象力。
PHP开发工程师
2022/03/24
5830
手把手带你走进Babel的编译世界
【Babel】293- 初学 Babel 工作原理
已经9102了,我们已经能够熟练地使用 es2015+ 的语法。但是对于浏览器来说,可能和它们还不够熟悉,我们得让浏览器理解它们,这就需要 Babel。
pingan8787
2019/07/25
4640
【Babel】293- 初学 Babel 工作原理
AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解
Javascript就像一台精妙运作的机器,我们可以用它来完成一切天马行空的构思。
Nealyang
2019/09/29
2.4K1
AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解
【Web技术】780- AST 实现函数错误自动上报
之前有身边有人问我在错误监控中,如何能实现自动为函数自动添加错误捕获。今天我们来聊一聊技术如何实现。先讲原理:在代码编译时,利用 babel 的 loader,劫持所有函数表达。然后利用 AST(抽象语法树) 修改函数节点,在函数外层包裹 try/catch。然后在 catch 中使用 sdk 将错误信息在运行时捕获上报。如果你对编译打包感兴趣,那么本文就是为你准备的。
pingan8787
2020/11/19
9870
【Web技术】780- AST 实现函数错误自动上报
JS代码之混淆
抽象语法树(Abstract Syntax Tree),简称 AST,初识 AST 是在一门网页逆向的课程,该课程讲述了 js 代码中混淆与还原的对抗,而所使用的技术便是 AST,通过 AST 能很轻松的将 js 源代码混淆成难以辨别的代码。同样的,也可以通过 AST 将其混淆的代码 还原成执行逻辑相对正常的代码。
愧怍
2022/12/27
22.5K0
JS代码之混淆
babel源码详解-v1.7.8
继续打开 github 看一下最初的版本的 babel 是怎么实现的,了解它的基本原理。
windliang
2022/09/23
7280
babel源码详解-v1.7.8
阿里面试官:如何给所有的async函数添加try/catch?
后来花了一些时间整理了下思路,那么如何实现给所有的async函数添加try/catch呢?
coder_koala
2022/11/28
1.1K0
阿里面试官:如何给所有的async函数添加try/catch?
探索:怎样将单个vue文件转换为小程序所需的四个文件(wxml, wxss, json, js)
比如JavaScript在执行之前,会经过词法分析和语法分析两个步骤之后,得到一个抽象语法树。
极乐君
2019/09/08
5.2K0
AST 与前端工程化实战
AST 是一个非常基础但是同时非常重要的知识点,我们熟知的 TypeScript、babel、webpack、vue-cli 都是依赖 AST 进行开发的。本文将通过 AST 与前端工程化的实战向大家展示 AST 的强大以及重要性。
用户1462769
2019/09/17
1.3K0
AST 与前端工程化实战
【编译技术】:解读 Babel AST Format——06
The Babel parser generates AST according to Babel AST format. It is based on ESTree spec with some deviations.
WEBJ2EE
2020/11/05
4830
【编译技术】:解读 Babel AST Format——06
前端插件机制剖析及业界案例分析
导语 如果你的工具型面对的对象有很丰富的场景需求,或者不想再为频繁的增减需求而频繁迭代,是时候考虑为你的系统设计一款插件系统。 插件机制 插件机制: Core-Plugin 架构的组成 Core:基础功能,提供插件运行的环境,管理插件的注册与卸载(可拔插)以及运行,也即管理插件的生命周期。 PluginApi:插件运行的接口,由 Core 抽象出来的接口。(颗粒度尽可能小) Plugin:每个插件都是一个独立的功能模块。 Core-Plugin 模式的好处,总结几点: 提高扩展性; 减少因功能改变而引起的
用户1097444
2022/06/29
7540
前端插件机制剖析及业界案例分析
创建 AST 节点写法示例
AST (Abstract Syntax Tree(抽象语法树)) 是源代码语法结构的一种抽象表示。不了解 AST 的,可以看这篇文章。
前端GoGoGo
2020/04/02
2.3K0
前端工程师需要了解的 Babel 知识
在前端圈子里,对于 Babel,大家肯定都比较熟悉了。如果哪天少了它,对于前端工程师来说肯定是个噩梦。Babel 的工作原理是怎样的可能了解的人就不太多了。
桃翁
2019/09/24
4730
前端工程师需要了解的 Babel 知识
【编译技术】:解读 Babel AST Format——05
The Babel parser generates AST according to Babel AST format. It is based on ESTree spec with some deviations.
WEBJ2EE
2020/11/05
1.5K1
【编译技术】:解读 Babel AST Format——05
相关推荐
Babel原理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验