window = this和global的区别 1.this-->module.exports 2.window.x=xxx用this输出会报错 一般补环境 window = global delete global ast抽象语法树 astexplorer.net 一棵树从file根节点开始,program代表所有代码,body下面expr...代表代码信息 babel是node.js的ast第三方库.。 打开官方文档将所有的工具进行安装。 安装 npm install @babel/types parser.parse将js代码转化成语法树 generator将语法树转化成js代码 types用来判断节点类型和生成新节点 https://blog.csdn.net/qq_26158277/article/details/120243558 蓝色的key叫节点在node.js中以node存在 variableDeclaration:变量声明节点 FunctionExpression:函数声明节点 BlockStatement:块语句(函数里面的块) identifier:标识符(变量) BreakStatement:中断语句break ContinueStatement:跳过语句continue update:更新表达式i++ test:二进制表达式,运算判断之类 ForStatment:for块for循环 IfStatment:判断 callExpression:函数调用 MeberExpression:对象的成员 new:NewExpression:new表达式 常用四种工具 generator:ast转js parse:js转ast traverse:节点遍历操纵 types:提供对象集合,操作生成节点 throw出错//最基础 //引入库 const parser = require('@babel/parser'); // const generator = require('@babel/generator',{ // retainLines:true,//保留行号 // comment:false,//保留注释 // compact:false,//正常压缩 // minified:true,//高压 // concise:false,//低压 // jsescOption:{} // }).default; //遍历 const traverse = require('@babel/traverse').default; const generator = require('@babel/generator').default; // //js代码转化为ast(sourceType:'module'不加这个在代码中有impoer时可能会报错) // const aaa = parser.parse('var a = 1;var b = 2;var c=3;',{sourceType:'module'}); // //替换 // const ast_code = aaa['program']['body'][1]['declarations'][0]['id']['name']='我是最牛逼'; // console.log(ast_code); // //ast转化为js // console.log(generator(aaa).code); // //throw 'end';报错 //遍历和替换 var js_code = 'a=1;a=2;a=3;a=4;'; const bl_ast = parser.parse(js_code); // console.log(bl_ast); //visitor自定义的方法 const visitor = { // ExpressionStatement(path){ // console.log(path.node.expression.right.value); // }, //遍历修改value值 NumericLiteral(path){ path.node.value = 100; console.log(path.node.value); }, //遍历修改key值 Identifier(path){ path.node.name = 'b' }, }; traverse(bl_ast,visitor); const result = generator(bl_ast).code; console.log(result);
const fs = require('fs'); const {parse} = require('@babel/parser'); const traverse = require('@babel/traverse').default; var js_code = fs.readFileSync('hx.js',{encoding:'utf-8'}); const generator = require('@babel/generator').default; const types = require('@babel/types'); const ast_code = parse(js_code); const visitor = { //深度优先,遍历两种节点 'ExpressionStatement|AssignmentExpression':{ enter(path){ console.log(path.toString()); console.log('1'); }, exit(path){ console.log(path.toString()); console.log('2') }, } //先遍历大节点再遍历小节点 //ArrayExpression:{ enter(path){ console.log(path.toString()) console.log(generator(path.node).code) console.log(path+''); //path方法 path.stop(); //自动识别替换path方法 path.replaceWith(types.valueToNode('1234445643333')) path.replaceWithSourceString('12344456fdsafa43333') //前插入 path.insertBefore(types.valueToNode('fdskhaksjfhksaka')) //后插入 path.insertAfter(types.valueToNode('kjjjjjjj')); path.stop() ///输出node对象 console.log(path.parent); // 输出path对象 console.log(path.parentPath) //打印父节点 console.log(path.parent.type) // path.findParent向上遍历父节点,直到找到,满足回调函数要求为止 result = path.findParent(function(result){return result.isExpressionStatement()}); console.log(result.type); //容器 key是当前节点在容器中的索引 listkey是容器的名字 只有节点是列表容易才有意义,否则会返回父节点 console.log(path.container); console.log(path.key); console.log(path.listkey) //判断是否是列表 console.log(path.inList()); //获得同级几点的第几个key的path,获得下一个同级节点path.getsibling(path.key+1) console.log(path.getsibling(0)+''); //获得当前作用域的引用值 path.evaluate() }}, Identifier(path){ //获得当前作用域的引用值 // console.log(path); if (path.node.name === 'a'){ console.log( path.evaluate()) }; }, // NumericLiteral(path){ //path删除节点(删除要保证ast节点的完整和流畅,要不然很容易报错) // path.remove(); //前插入 // }, }; // const visitor = { // ArrayExpression:{ // enter(path){ // console.log('1'); // }, // exit(path){ // console.log('2') // }, // } // }; traverse(ast_code,visitor); const result_js_code = generator(ast_code).code; console.log(result_js_code); // //自动生成节点 // console.log(types.valueToNode('1234445643333')); // throw '';
//babel库及文件模块导入 const fs = require('fs'); //babel库相关,解析,转换,构建,生产 const parser = require("@babel/parser"); const traverse = require("@babel/traverse").default; const t = require("@babel/types"); const types = require("@babel/types"); const generator = require("@babel/generator").default; let jscode = fs.readFileSync('./hx.js', {encoding: "utf-8"}); let ast = parser.parse(jscode); // let obj = { // name: 'demo', // add: function (a, b) { // return a + b + 1000; // }, // mul: function (a, b) { // return a * b + 1000; // }, // }; // types组件练习。判断节点类型和生成新的节点 // &&表示and // path.xxx取的是key里面的值,其他的都是value中的值 traverse(ast,{ enter(path){ //修改name的值 if (types.isIdentifier(path.node)&& path.node.name === 'a'){ path.node.name = '我是sm'; } //代码第二种形式 if(types.isIdentifier(path.node,{name:'a'})){ path.node.name = '我是sp' }; //断言形式(报错) // types.assertIdentifier(path.node) } }); aa = generator(ast).code; console.log(aa); // 生成新的节点 let a = t.identifier('我是sp'); let b = t.identifier('b'); let binExpr2 = t.binaryExpression("+", a, b); let binExpr3 = t.binaryExpression("*", a, b); let retSta2 = t.returnStatement(t.binaryExpression("+", binExpr2, t.numericLiteral(1000))); let retSta3 = t.returnStatement(t.binaryExpression("+", binExpr3, t.numericLiteral(1000))); let bloSta2 = t.blockStatement([retSta2]); let bloSta3 = t.blockStatement([retSta3]); let funcExpr2 = t.functionExpression(null, [a, b], bloSta2); let funcExpr3 = t.functionExpression(null, [a, b], bloSta3); let objProp1 = t.objectProperty(t.identifier('name'), t.stringLiteral('test')); let objProp2 = t.objectProperty(t.identifier('add'), funcExpr2); let objProp3 = t.objectProperty(t.identifier('mul'), funcExpr3); let objExpr = t.objectExpression([objProp1, objProp2, objProp3]); let varDec = t.variableDeclarator(t.identifier('obj'), objExpr); let loaclAst = t.variableDeclaration('let', [varDec]); let code = generator(loaclAst).code; console.log(code); 定义了一些其他字面良 还可以是其他类型 let node = t.valueToNode(([1,false,{'x':100}])); let code = generator(node).code; console.log(code); path和node的区别 const updateParamNameVisitor = { Identifier(path) { if (path.node.name === this.paramName) { path.node.name = "x"; } console.log(path); path.stop(); } }; const visitor = { FunctionExpression(path) { const paramName = path.node.params[0].name; path.traverse(updateParamNameVisitor, { paramName }); } }; traverse(ast, visitor); // path中的方法 // 获得子节点 // 此二项表达式为a+b+1000 const visitor ={ BinaryExpression(path){ // 获得节点属性 console.log(path.node.left.name); const paramName = path.node.left.name; console.log(path.node.left.right.operator); // 获得节点属性 console.log(path.get('left')) // 判断path对象的类型 const aa = path.get('right').isNumericLiteral(); console.log(path.get('right')) // path转换为js代码 }; } }; function aa (a,b){ var cc =1; return '我是sm' }; const visitor = { let obj = { n: 'demo', add: function (a, b) { var cc = 11; return a + b + 1000; }, mul: function (a, b) { return a * b + 1000; }, }; ReturnStatement(path) { // console.log(path.node); //直接打印属性 console.log( path.node.argument.value); //直接替换节点属性 path.node.argument.value = t.identifier('aaaasb'); } // 节点一换一 BinaryExpression(path){ path.replaceWith(t.valueToNode(1111)) } // 节点多换一('一个节点替换成了两个节点') ReturnStatement(path){ path.replaceWithMultiple([ t.returnStatement(),t.expressionStatement(t.valueToNode('rewafsaafda')), ]); } // 用字符串来替换节点 ReturnStatement(path){ let argumentPath = path.get('argument'); argumentPath.replaceWithSourceString( '1aaaa' ); path.stop() } // 删除节点 ReturnStatement(path){ path.remove() } // 插入节点 ReturnStatement(path){ path.insertBefore(t.expressionStatement(t.valueToNode("qqqqq" ))) path.insertAfter(t.expressionStatement(t.valueToNode('After!'))) } //父级path ReturnStatement(path){ //向上逐层遍历父级节点,当回调函数返回true时,输出当前path对象 console.log(path.findParent((p) => p.isObjectExpression()).toString()) //与findParent类似,多了一个遍历当前节点 path.find(); //向上查找最接近的父函数,返回一个path对象 path.getFunctionParent(); //向上查找最接近的语句,返回一个path对象 path.getStatementParent() } //同级path。引入container概念,path相当于数组,container相当于一个数组,listkey是数组的名字,key是在节点当中的位置。badu = ['11','222'] ReturnStatement(path){ //判断是否有同级节点。注意数组有且只有一个成员时返回true console.log(path.inList); //获得容器;获得当前节点在容器中的索引;获得容器名 console.log(path.container); console.log(path.listKey); console.log(path.key); //获得同级节点的path对象 path.getSibling('VariableDeclarator'); //容器内节点的前后插入节点 path.parentPath.unshiftContainer('body',[t.expressionStatement(t.stringLiteral('Before1')),t.expressionStatement(t.stringLiteral('Before2'))]); console.log(path.parentPath.pushContainer('body',t.expressionStatement(t.stringLiteral('After')))) } }; const visitor = { //scope详解 //获得标识符的作用域。可以看出来e的作用范围就在add函数中 Identifier(path){ if (path.node.name === 'e'){ console.log(generator(path.scope.block).code) } } // 获得函数的作用域。只有一个函数 FunctionDeclaration(path){ console.log(generator(path.scope.parent.block).code) } //获取标识符的绑定。接受一个字符串并获取其的绑定,如果传的值应用不到或者应用不到就会返回undefined FunctionDeclaration(path){ //kind:表明了a是一个参数,并不代表是当前domo函数的参数,实际上在js源码种a是add函数的参数(当函数中局部变量和全局变量重名时,使用局部变量) // referenced:当前标识符是否被引用references当前标识符被引用的次数 //constant:是否是常量 //scope:作用域 let bind = path.scope.getBinding('a'); console.log(bind); console.log('12'); //作用域参数获取 let ba = path.scope.getBinding('a'); let bo = path.scope.getBinding('demo'); console.log(ba.referenced); console.log(ba.references); console.log(generator(ba.scope.block).code); console.log(generator(bo.scope.block).code); //获取当前节点自己的一个绑定,不包含父级 path.traverse({Identifier(p){ let name = p.node.name; console.log(name,!!p.scope.getOwnBinding(name)); }}) } }; traverse(ast, visitor); console.log(generator(ast).code); //一般使用getBinding替代getOwnBinding,只需加上作用域判断来只取当前节点的标识符绑定 function TestOwnBinding(path){ path.traverse({ Identifier(p){ let name = p.node.name; let binding = p.scope.getBinding(name); binding && console.log( name, generator(binding.scope.block).code == path + '' ); // path.stop() } }) } traverse(ast,{ FunctionExpression(path){ TestOwnBinding(path); } }); //referencePaths,constantViolations //引用标识符的节点全部存放在referencePaths种 //修改标识符的几点全部存放在constantViolations traverse(ast,{ FunctionDeclaration(path){ let binding = path.scope.getBinding('a'); binding.scope.traverse(binding.scope.block,{ AssignmentExpression(p) { if (p.node.left.name == 'a'){ p.node.right = t.numericLiteral(50444440) } } }) } }); console.log(generator(ast).code); //标识符重命名 traverse(ast,{ Identifier(path){ //直接命名 let binding = path.scope.getBinding('b'); console.log(generator(binding.scope.block).code); binding.scope.rename('b','x'); console.log('123'); console.log(generator(binding.scope.block).code); //直接命名可能造成标识符冲突用generateUidIdentifier即可避免 // path.scope.generateUidIdentifier("uid"); // console.log('123'); console.log(path.scope.generateUidIdentifier('abc').name) } }); console.log(generator(ast,).code);
04-13
269
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
01-30
783
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交