JavaScript 获得代码行号和脚本文件名

比如要写一个 JavaScript 的日志输出工具,在方法 log.info() 中能得到调用它所在的文件和代码行号。和众多的日志工具一样,像 log4j, 都是在程序代码中主动抛出异常,然后从异常栈中去查找到调用者所在的代码行和文件名。 不过也就刚刚才了解到 JavaScript V8 引擎提供了自己的 StackTrace API,Chrome 和 Node.js 可用。 先来看可通用的 JavaScript  抛异常 throw new Error() 的方式,下面的代码:
 1var log = {
 2    info: function(arg){
 3        try {
 4            throw new Error();
 5        } catch (e) {
 6            alert("Stack:" + e.stack);
 7            var loc= e.stack.replace(/Error\n/).split(/\n/)[1].replace(/^\s+|\s+$/, "");
 8            alert("Location: "+loc+"");
 9        }
10    }
11};
12
13function foo(){
14    log.info(123);
15}
16
17foo();
点击链接 http://jsfiddle.net/Unmi/53xas/ 执行,其中是用 document.write() 输出的,完整异常栈是:
1Error
2    at Object.log.info (http://fiddle.jshell.net/_display/:24:19)
3    at foo (http://fiddle.jshell.net/_display/:39:9)
4    at window.onload (http://fiddle.jshell.net/_display/:42:1)
并且成功定位到调用者代码行是
1Location: Object.log.info (http://fiddle.jshell.net/_display/:24:19)
上面是在 Chrome 中运行的效果,在 Firefox/Safari 中有所不同,是用 @ 代替了 at,所以在 Fairfox/Safari 中输出的异常栈是
1window.onload/log.info@http://fiddle.jshell.net/_display/:24
2foo@http://fiddle.jshell.net/_display/:39
3window.onload@http://fiddle.jshell.net/_display/:42
得到代码行
1Location: foo@http://fiddle.jshell.net/_display/:39
注意,我都是在 fiddle.jshell.net 上测试我的 JavaScript 代码,fiddle 相当于拿到你的脚本生成一个文件来执行的, 所以脚本文件都成了 fiddle 上的某个脚本文件,实际应用中就是你的文件的 URL,比如 special.js。

上面可以稍加改造作为一个简单的日志工具来使用,再辅以传入参数 JSON 序列化 和 Ajax 提交消息到后台,就完整了。

每次想到日志工具,不能不想到各种 log4XX,如 log4j, log4php, log4perl, log4cpp 等不一而足。那么有没有 log4javascript 呢,当然有, 那就是 http://log4javascript.org/。 这个工具不错,提供了 Popup 或 In-page console 不同颜色级别来显示日志,也可以把日志用 Ajax 发送到后面记录在服务端,并能记录异常,显示出错所在行和文件。

如果你使用的是 V8 引擎,Chrome 和 Node.js 所用的,那么你可以利用 JavaScriptStackTraceApi 来获得行号信息,有两个 API:

Error.captureStackTrace()
Error.prepareStackTrace()

在 Chrome 中可运行下面的代码:
 1var getStackTrace = function() {
 2  var obj = {};
 3  Error.captureStackTrace(obj, getStackTrace);
 4  return obj.stack;
 5};
 6
 7function foo(){
 8    return getStackTrace();
 9}
10
11alert("Stack:" + foo());
12alert("Location:" + foo().split(/\n+/)[1].replace(/(^\s+|\s+$)/,""));
点击链接 http://fiddle.jshell.net/Unmi/EE9gM/  在 Chrome 中运行类似的代码。在 Firefox/Safari 中得不到结果。

参考:1. JavaScript new Exception(name,message)
          2.  Javascript中获取出错代码所在文件及行数 永久链接 https://yanbin.blog/javascript-get-execution-line-file/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。