1. 前言
babel 如今已成为每一个现代前端项目的标配, 有了它,我们可以肆无忌惮的使用 stage-xxxx
的语法, 增强我们的生产力
我们通过写一个 支持 arr[-1]
的 babel插件 来加深理解
2. 需要实现的功能
现在我们有如下的一个数组 arr
, 我们想获取数组的最后一个下标,由于 js
不支持 [-1]
的操作,所以我们需要转换成 arr[arr.length - 1]
1 | const arr = [1,2,3] |
换作以前的我, 反手就是粗暴的 正则解析 去替换, 当然正规一点还是老老实实用 AST(Abstract Syntax Tree)
3. 查看抽象语法树
站在巨人的肩膀上 我们可以 使用 在线的 AST 生成工具 https://astexplorer.net/ 可以看到我们刚才写的两行代码对应的 语法树
当然你也可以使用 @babel/core
来生成 语法树 得到的结果是一致的
1 | import babel from '@babel/core' |
4. 编写插件
关于 babel 插件的详细介绍, 可以参考 这篇文章 Babel 插件有啥用?
1 | const babel = require('@babel/core') |
@babel/types
主要帮助我们判断 当前节点是什么类型, 十分强大, 根据观察生成 的 AST
, arr[-1]
是一个 MemberExpression
节点, 所以我们只需要 将对应的节点 替换掉即可
想要将 arr[-1]
转换成 arr[arr.length - 1]
, 我们需要知道2点
数组的名字 => arr
数组的下标并且是一个数字 => -1
获取 数组的名字
1 | if (node.object && t.isIdentifier(node.object)) { |
获取 数组的下标, 应该满足 是一个表达式, 并且参数是一个数字
1 | let arrIndex |
最后拿到了我们想要的参数, 组装一下, 替换当前节点即可
1 | const result = `${arrName}[${arrName}.length ${operator} ${arrIndex}]` |
5. 测试
1 | import { transform } from '@babel/core' |
6. 特殊的场景
在实际场景中 可能还要直接赋值的情况
1 | arr[-1] = 4 |
或者使用 lodash
的 get
的情况
1 | get(arr,"[0]") |
这样对应的 AST
会有变化, 还需要处理对应的节点
7. 使用
1 | yarn add babel-plugin-array-last-index |
1 | // .babelrc |
8. 结语
这是我第一次尝试写一个玩具插件,虽然实际作用不大, 不过还是学到不少, 也由衷的佩服那些 写 正儿八经 babel
的插件的作者, 是真的强!