AST 变量 enter 和 exit 的区别 退出区别

发布时间 2023-11-24 21:42:13作者: 守护式等待

1.enter方式进行遍历(不写默认是enter方式)

假设我们需要处理的代码如下:

var a = 'a' + 'b' + 'c' + d + 'e' + 'f';

想要对上面的 代码 进行字符串的合并操作,遍历 BinaryExpression类型,代码如下:

const visitor = {
    "BinaryExpression"(path) {
        console.log(path.toString())
        const {confident, value} = path.evaluate();
        confident && path.replaceWith(types.valueToNode(value));
    },
}

traverse(ast, visitor);

我们知道,当没有指明以什么方式进行遍历时,会默认以enter方式进行遍历,上面的插件运行结果如下:

最后处理后的代码变成了这样:

var a = "abc" + d + 'e' + 'f';

我们在插件的第一行打印出了当前所遍历path的源代码,可以看到①②③④是按顺序进行遍历的,是逐渐向底部进行遍历,直到无法遍历。可以将上面的代码略微的调整下:

var a = 'a' + 'b' + 'c' + 'd' + 'e' + 'f';

再次运行上面的插件,打印的结果如下:

这一次为什么只遍历了一次呢?那是因为第一次遍历后,结果变成了一个 StringLiteral 类型的表达式,

var a = 'abcdef';

已不再是 BinaryExpression 类型,因此不会再次遍历。甚至可以将path的left节点和right节点分别打印出来看看效果:

const visitor = {
    "BinaryExpression"(path) {
        console.log(path.get('left').toString());
        console.log(path.get('right').toString());
        const {confident, value} = path.evaluate();
        confident && path.replaceWith(types.valueToNode(value));
    },
}

traverse(ast, visitor);

2.exit方式进行遍历

当指明以exit方式进行遍历时,插件及部分代码如下:

const visitor = {
    "BinaryExpression": {
        exit: function (path) {
            console.log(path.toString())
            const {confident, value} = path.evaluate();
            confident && path.replaceWith(types.valueToNode(value));
        }
    },
}

traverse(ast, visitor);

很明显和上面enter方式遍历的顺序不一样,大致分析如下:

  1. left : 'a'; right:'b'                   --->   结果合并为'ab'。

  2. left : 'ab'; right:'c'                  --->   结果合并为'abc'。

  3. left : 'abc'; right:d                 --->   结果没法合并,但他们已经成为一个整体 'acb' + d

  4. left : 'abc'+d; right:'e'           --->   结果没法合并,但他们已经成为一个整体 'acb' + d + 'e';

  5. left : 'abc'+d + 'e'; right:'f'   --->   结果没法合并,但他们已经成为一个整体 'acb' + d + 'e'  + 'f';

  6. 不再是BinaryExpression 类型,停止遍历。

上面的left和right表示BinaryExpression 类型的左右子节点。

我画了个示意图,大家可以看看: