需求

  1. 学习已有项目/框架时, 想要分析代码所有运行;
  2. 开发项目逻辑分析, 排错.

项目地址

Github

效果

思路

  1. 将代码转换为抽象语法树
  2. 根据需要对语法树进行修改
  3. 将语法树转换为代码

实现

const fs = require('fs')
const escodegen = require("escodegen");
const esprima = require('esprima');const srcPath = "./demo/three.js";
const destPath = './demo/three_log.js';
/** 是否显示堆栈信息 */
const isShowStack = false;
let prevHandleTime = 0;main(srcPath, destPath);function main(srcPath, destPath) {log('读取文件');const program = fs.readFileSync(srcPath, "utf-8");log('文本转AST');let tree = esprima.parseScript(program);log('处理AST');handleTree(tree);log('AST转文本');const result = escodegen.generate(tree);// console.log(result);log('写入新文本');fs.writeFileSync(destPath, result);log('Finish');
}function handleTree(tree, methodName = "") {if (!tree) return;if (checkIsObject(tree)) {switch (tree.type) {case 'BlockStatement':if (tree.body && checkIsArray(tree.body)) {let logStr = '';if (isShowStack) {logStr =`console.groupCollapsed("---------------------------------${methodName}");  console.trace("${methodName}");console.groupEnd(); `;} else {logStr = `console.log("---------------------------------${methodName}");`;}const consoleBody = esprima.parseScript(logStr).body;if (tree.body.length > 0) {// 空方法不添加log for (let i = consoleBody.length - 1; i >= 0; i--)tree.body.unshift(consoleBody[i]);}handleTree(tree.body, methodName);return;}break;case 'AssignmentExpression':tree.right && handleTree(tree.right, getName(methodName, tree.left));break;case 'CallExpression':if (tree.callee) {handleTree(tree.callee, methodName);}if (tree.arguments) {handleTree(tree.arguments, methodName);}break;case 'ClassDeclaration':tree.body && handleTree(tree.body, getName(methodName, tree));break;default:tree.body && handleTree(tree.body, methodName);break;}return;}if (checkIsArray(tree)) {for (let i = 0; i < tree.length; i++) {let item = tree[i];switch (item.type) {case 'MethodDefinition':if (item.kind === 'get' || item.kind === 'set') {// 过滤 get/set 方法} else {item.value && handleTree(item.value, getName(methodName, item));}break;case 'ExpressionStatement':item.expression && handleTree(item.expression, methodName);break;case 'ClassDeclaration':item.body && handleTree(item.body, getName(methodName, item));break;case 'ForStatement':case 'ForInStatement':// for 语句不添加break;case 'FunctionDeclaration':// 方法声明item.body && handleTree(item.body, getName(methodName, item));break;default:item.body && handleTree(item.body, methodName);break;}}return;}console.error('什么鬼');
}function getName(methodName, item) {let itemName = '';if (item) {if (item.id)itemName = item.id.name;else if (item.key)itemName = item.key.name;else if (item.property)itemName = item.property.name;}let dot = '';if (methodName && itemName)dot = '.';return methodName + dot + itemName;
}function checkIsArray(arr) {return Object.prototype.toString.call(arr) === '[object Array]';
}function checkIsObject(obj) {return Object.prototype.toString.call(obj) === '[object Object]';
}function getTime() {const now = Date.now();let result = 0;if (prevHandleTime !== 0) {result = now - prevHandleTime;}prevHandleTime = now;return '  ' + result + ' ms';
}function log(str) {console.log(str, getTime());
}

拓展

灵活使用, 可大幅提高分析效率, 如:

  1. 字符串排除打印;
  2. 重复不打印;
  3. 指定时间打印;

JavaScript打印所有被执行函数堆栈相关推荐

  1. JavaScript中的立即执行函数

    原文链接 通常我们声明一个函数有以下几种方式: // 声明函数f1 function f1() {console.log("f1"); } // 通过()来调用此函数 f1();/ ...

  2. 深入理解javascript中的立即执行函数(function(){…})()

    2019独角兽企业重金招聘Python工程师标准>>> javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花,当然,能理解各 ...

  3. JavaScript基础之立即执行函数

    在JavaScript中有时候看到一些很神奇的函数比如下面截图: 这种函数只要浏览器加载的时候会自动运行,而需要调用,前面在闭包的时候也说过这种函数,一般将其称之为:立即执行函数. 立即函数的特征: ...

  4. 对于javaScript闭包,立即执行函数的用法的一些理解

    最近在刷freeCodeCamp上面的题目,发现了这么一道有趣的题目,加深了我对于js中闭包和立即执行表达式的一些理解,题目如下: 给一个正整数num,返回小于或等于num的斐波纳契奇数之和. 斐波纳 ...

  5. JavaScript中的自执行函数和闭包实现过程

    在JS中,也常常需要复用,将一些常见的操作封装起来,目前看到的很多JS库,比如JQuery就是非常典型的,那么如何在JS中写一个可复用的呢?虽然在JS中有类的这个说法,但是我对这个玩意还是很抵触的,但 ...

  6. js中立即执行函数会预编译吗_作为前端你了解JavaScript运行机制吗?

    作为前端工程师,大家都知道js是前端一开始就要学会的知识点,js的代码你会写了,那js的运行机制你了解吗?只有了解了js的运行机制,才能在工作中如鱼得水,今天就跟随珠峰的老师一起来了解下js的运行机制 ...

  7. JavaScript重难点解析2(立即执行函数IIFE,this关键字)

    JavaScript重难点解析2(立即执行函数IIFE,this关键字) 立即执行函数 this关键字 立即执行函数 也叫做匿名函数自调用,可以在定义一段函数之后直接让其执行. ;(function ...

  8. JavaScript之立即执行函数

    我们知道,在一般情况下,函数必须先调用才能执行,如下所示,我们定义了一个函数,并且调用, function fn(){console.log(1);}fn(); 打印结果为:         如果不调 ...

  9. JavaScript自执行函数,自执行函数是什么,存在的意义?

    JavaScript自执行函数 1.自执行函数是什么 2.自执行函数存在的意义 2.1封装 3.自执行函数两种常见的的写法 3.1自执行函数的第一种写法 3.2自执行函数的第二种写法 4.自执行函数的 ...

最新文章

  1. 基于caffe的度量学习实现(Siamese network Triplet network)
  2. 重温Vue-router
  3. Windoes 10 笔记本上安装telnet方法
  4. LCD MIPI DSI时钟计算
  5. Learning to rank在淘宝的应用
  6. pdf转word网站,亲测有效
  7. Git初始配置【一】
  8. boost::hana::capture用法的测试程序
  9. springboot+vue的前后端分离与合并方案
  10. 前端学习(576):margin无效情形之内联特性导致无效
  11. 将视图转为image_使用视图绑定替代 findViewById
  12. 剖析:3D游戏建模的千奇百变,带你快速入门
  13. java request 克隆_Java 复制HttpServletRequest InputStream的方法 只需2步轻松搞定
  14. u3d中如何添加avatar和状态机
  15. Unicode字符集和编码方式
  16. 创业公司如何构建数据指标体系?
  17. c语言中的空字符常量,c习题编译时出现空的字符常量,怎么修改?
  18. C#ObjectArx Cad将图形范围缩放至指定实体
  19. 腾讯php开发工程师面试题
  20. 【前端】html+css实现鼠标悬浮变色的按钮,消除加粗边框发生抖动现象的两种方法 hover【HTML+CSS+JavaScript(JS)】

热门文章

  1. jyy的计算机系统基础里面在pa0分支下与master分支diff操作的更正
  2. 【攻克Dota2】OpenAI自学习多智能体5v5团队战击败人类玩家
  3. hbase的rowkey设计原则及热点问题
  4. [学习收藏]Linux系统硬盘优化
  5. 云上未来 | 有孚网络助力构建云生态
  6. MongoDB可视化管理工具-MongoDB Compass
  7. Web报表系统葡萄城报表:报表平台
  8. 固安凤凰机器人_世界500强实力布局固安 保利京津冀成功摘得固安核心地块
  9. springboot集成mybatis-plus
  10. NAT/NAPT地址转换(内外网通信)技术详解【华为eNSP】