今天我们来学习一下
作用域Scope 与 被绑定量Binding
作用域 Scope
@Babel解析出来的语法树节点对象会包含作用域信息,这个信息会作为节点Node对象的一个属性保存
这个属性本身是一个Scope对象,其定义位于node_modules/@babel/traverse/lib/scope/index.js中
执行 Scope.dump(),会得到自底向上的 作用域与变量信息
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;const jscode = `
function squire(i){return i * i * i;
}
function i()
{var i = 123;i += 2;return 123;
}
`;
let ast = parser.parse(jscode);
const visitor = {"FunctionDeclaration"(path){console.log("\n\n这里是函数 ", path.node.id.name + '()')path.scope.dump();}
}traverse(ast, visitor);
运行之后,这个只是一部分
每一个作用域都以#标识输出
每一个绑定都以-标识输出
先输出当前作用域,再输出父级作用域,再输出父级的父级作用域,以此类推
我在说一下 { constant: true, references: 3, violations: 0, kind: 'param' } 这个语句里面的代码
FunctionDeclaration 表示这是一个函数声明。
- i 指的是函数 squire 的一个参数名为 i。
{ constant: true } 表示这个参数 i 在函数体内部没有被重新赋值,它是一个常量。如果是 false,就说明在函数体内被赋值了
{ references: 3 } 表示在函数体内部,i 被引用了3次。
{ violations: 0 } 表示没有违反任何特定的编码规则或最佳实践。
{ kind: 'param' } 表示 i 是一个函数行参。
接下来说一下
Program
- squire
- i
Program 表示这是关于整个程序的信息,而不是单个函数。
- squire 表示 squire 函数在程序中的状态。
{ constant: true } 表示 squire 函数在程序中没有在赋值给它,它是一个常量。
{ references: 0 } 表示在程序的其它部分,squire 函数没有被引用。
{ violations: 0 } 表示没有违反任何特定的编码规则或最佳实践。
{ kind: 'hoisted' } 表示 squire 函数是一个在执行前被提升到其作用域顶部的函数声明。{ kind: 'var' }表示是一个var声明变量
接下来我们来说一下i函数
i()函数里面有两个声明变量,分别是a和i,很明显变量i是被重新赋值了的,所以他的constant是false
{ violations: 1 } 表示有一个编码规则或最佳实践的违反。
我们来看看scope中的getBinding中的用法
`const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;
const jscode = var a = 1; var b = 2; function squire(){ var c = 3; var d = 4; return a * d; var e = 5; } var f = 6;
;
let ast = parser.parse(jscode);
const visitor = {
VariableDeclarator(path)
{
const func_name = path.node.id.name;
const binding = path.scope.getBinding(func_name);
// 如果变量没有被引用过,那么删除也没关系
// 此处不能用有无修改过进行判断,因为没有被修改过并不意味着没用
if(binding && !binding.referenced){
//binding存在并且,binding中的referenced属性为false,意思是该变量没有被引用
path.remove();
}
},
}
traverse(ast, visitor);
console.log(generator(ast)['code']);`
这里使用了Scope.getBinding()方法来获取Binding对象, 判断其引用情况来对语法树进行修改
其他用法可以参考蔡老板的教程
蔡老板的教程:https://mp.weixin.qq.com/s/yFcSXmXChGNaT7wPlaj0uw
今天就先记录到这里,拜拜~
蔡老板的教程