如何获得JavaScript调用者函数行号? 如何获得JavaScript调用者的源URL?
我正在使用以下获取JavaScript调用方函数名称:
var callerFunc = arguments.callee.caller.toString(); callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous")
有没有办法find调用方法的行号?
另外,有没有一种方法来获取方法被调用的JavaScript文件的名称? 或者源URL?
kangax的解决scheme引入了不必要的try..catch作用域。 如果您需要访问JavaScript中的行号(只要您使用Firefox或Opera),只需访问(new Error).lineNumber
。
这在Chrome / QtWebView中适用于我
function getErrorObject(){ try { throw Error('') } catch(err) { return err; } } var err = getErrorObject(); var caller_line = err.stack.split("\n")[4]; var index = caller_line.indexOf("at "); var clean = caller_line.slice(index+2, caller_line.length);
我感到惊讶的是,大多数这些答案都假设你想要处理一个错误,而不是仅仅为正常情况输出有用的debugging痕迹。
例如,我喜欢用这样的console.log
包装器:
consoleLog = function(msg) {//See https://stackoverflow.com/a/27074218/470749 var e = new Error(); if (!e.stack) try { // IE requires the Error to actually be thrown or else the // Error's 'stack' property is undefined. throw e; } catch (e) { if (!e.stack) { //return 0; // IE < 10, likely } } var stack = e.stack.toString().split(/\r\n|\n/); if (msg === '') { msg = '""'; } console.log(msg, ' [' + stack[1] + ']'); }
这最终将输出如下所示打印到我的控制台:
1462567104174 [getAllPosts@http://me.com/helper.js:362:9]
请参阅https://stackoverflow.com/a/27074218/以及包含正确行号的console.log的正确包装?;
这通常是通过从当前上下文中抛出一个错误来实现的。 然后分析错误对象的属性,如lineNumber
和fileName
(一些浏览器有)
function getErrorObject(){ try { throw Error('') } catch(err) { return err; } } var err = getErrorObject(); err.fileName; err.lineNumber; // or `err.line` in WebKit
不要忘记, callee.caller
属性已被弃用(并且从来没有真正在ECMA第三编辑首先)。
另外请记住函数反编译被指定为依赖于实现,所以可能会产生相当意想不到的结果。 我在这里和这里写了关于它。
看起来我有点晚了:),但讨论是非常有趣的,所以..这里去…假设你想要build立一个error handling程序,并使用自己的exception处理程序类如:
function errorHandler(error){ this.errorMessage = error; } errorHandler.prototype. displayErrors = function(){ throw new Error(this.errorMessage); }
而你正在包装你的代码是这样的:
try{ if(condition){ //whatever... }else{ throw new errorHandler('Some Error Message'); } }catch(e){ e.displayErrors(); }
很可能你会在一个单独的.js文件中有error handling程序。
您会注意到,在firefox或chrome的错误控制台中,代码行号(和文件名)显示的是引发“错误”exception的行(file),而不是您想要debugging的“errorHandler”exception简单。 抛出你自己的exception是好的,但是在大型项目中定位它们可能是一个相当大的问题,特别是如果它们有类似的信息。 所以,你可以做的是将一个实际的空的错误对象的引用传递给你的error handling程序,该引用将保存所有你想要的信息(例如在Firefox中你可以得到文件名和行号等等。 ;在chrome中,如果你阅读Error实例的'stack'属性,你会得到类似的东西)。 长话短说,你可以做这样的事情:
function errorHandler(error, errorInstance){ this.errorMessage = error; this. errorInstance = errorInstance; } errorHandler.prototype. displayErrors = function(){ //add the empty error trace to your message this.errorMessage += ' stack trace: '+ this. errorInstance.stack; throw new Error(this.errorMessage); } try{ if(condition){ //whatever... }else{ throw new errorHandler('Some Error Message', new Error()); } }catch(e){ e.displayErrors(); }
现在你可以得到引发你自定义exception的实际文件和行号。
如果您想知道用于debugging的行号,或仅在开发过程中(出于某种原因),可以使用Firebug (Firefox扩展)并抛出exception。
编辑 :
如果你真的需要在生产中出于某种原因这样做,你可以预先处理你的JavaScript文件,以便每个函数跟踪它所在的行。 我知道一些发现代码覆盖率的框架(比如JSCoverage )。
例如,假设您的原始电话是:
function x() { 1 + 1; 2 + 2; y(); }
你可以写一个预处理器,使其成为:
function x() { var me = arguments.callee; me.line = 1; 1 + 1; me.line = 2; 2 + 2; me.line = 3; y(); }
然后在y()
,可以使用arguments.callee.caller.line
来知道它被调用的行,例如:
function y() { alert(arguments.callee.caller.line); }
行号实际上是静态的,所以如果你只是想要它的日志logging,那么它可以预先处理像吞咽。 我已经写了一个小gulp 插件 ,完全是这样的:
var gulp = require('gulp'); var logLine = require('gulp-log-line'); gulp.task('log-line', function() { return gulp.src("file.js", {buffer : true}) //Write here the loggers you use. .pipe(logLine(['console.log'])) .pipe(gulp.dest('./build')) }) gulp.task('default', ['log-line'])
这会将文件名和行添加到console.log中的所有日志中,所以console.log(something)
将变成console.log('filePath:fileNumber', something)
。 好处是,现在你可以连接你的文件,把它们传送出去,而你仍然可以得到这条线
这是我根据在这个论坛上find的信息写的:
这是MyDebugNamespace的一部分,Debug显然是保留的,不会作为命名空间的名字。
var DEBUG = true;
…
if (true == DEBUG && !test) { var sAlert = "Assertion failed! "; if (null != message) sAlert += "\n" + message; if (null != err) sAlert += "\n" + "File: " + err.fileName + "\n" + "Line: " + err.lineNumber; alert(sAlert); }
…
如何打电话:
MyDebugNamespace.Assert(new Error(""), (null != someVar), "Something is wrong!")
我包含了两个函数,可变数目的参数在我的名字空间中调用这个基本代码,以便可选地忽略调用中的消息或错误。
这与Firefox的工作正常,IE6和Chrome报告文件名和lineNumber为未定义。
下面的代码在Mozilla和Chrome中适用于我。
它的日志function,显示文件的名称和调用者的行。
log: function (arg) { var toPrint = []; for (var i = 0; i < arguments.length; ++i) { toPrint.push(arguments[i]); } function getErrorObject(){ try { throw Error('') } catch(err) { return err; } } var err = getErrorObject(), caller; if ($.browser.mozilla) { caller = err.stack.split("\n")[2]; } else { caller = err.stack.split("\n")[4]; } var index = caller.indexOf('.js'); var str = caller.substr(0, index + 3); index = str.lastIndexOf('/'); str = str.substr(index + 1, str.length); var info = "\t\tFile: " + str; if ($.browser.mozilla) { str = caller; } else { index = caller.lastIndexOf(':'); str = caller.substr(0, index); } index = str.lastIndexOf(':'); str = str.substr(index + 1, str.length); info += " Line: " + str; toPrint.push(info); console.log.apply(console, toPrint); }
我对JavaScript中自定义错误的贡献:
-
首先,我同意这个@BT的人inheritanceError对象 – 消息属性在哪里? ,我们必须正确地构build它(实际上你必须使用一个js对象库,我最喜欢的是: https : //github.com/jiem/my-class ):
window.g3 = window.g3 || {}; g3.Error = function (message, name, original) { this.original = original; this.name = name || 'Error.g3'; this.message = message || 'A g3.Error was thrown!'; (original)? this.stack = this.original.stack: this.stack = null; this.message += '<br>---STACK---<br>' + this.stack; }; var ClassEmpty = function() {}; ClassEmpty.prototype = Error.prototype; g3.Error.prototype = new ClassEmpty(); g3.Error.prototype.constructor = g3.Error;
-
那么我们应该定义一个全局的error handling函数(可选),否则他们将会终止于引擎:
window.onerror = printError; function printError(msg, url, line){ document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line; return true; }
-
最后,我们应该谨慎地抛出我们的习俗错误:
//hit it! //throw new g3.Error('Hey, this is an error message!', 'Error.Factory.g3'); throw new g3.Error('Hey, this is an error message!', 'Error.Factory.g3', new Error());
只有在传递第三个参数作为new Error()
我们才能看到带有函数和行号的堆栈!
在2时,函数也可以处理引擎引发的错误。
当然,真正的问题是我们是否真的需要它,什么时候需要。 有一些案例(我认为是99%),在这种情况下,优美的false
回报是足够的,只留下一些关键的问题,以便引发错误。
例如: http : //jsfiddle.net/centurianii/m2sQ3/1/
我就是这样做的,我已经在Firefox和Chrome上testing过了。 这使得可以检查函数被调用的地方的文件名和行号。
logFileAndLineNumber(new Error()); function logFileAndLineNumber(newErr) { if(navigator.userAgent.indexOf("Firefox") != -1) { var originPath = newErr.stack.split('\n')[0].split("/"); var fileNameAndLineNumber = originPath[originPath.length - 1].split(">")[0]; console.log(fileNameAndLineNumber); }else if(navigator.userAgent.indexOf("Chrome") != -1) { var originFile = newErr.stack.split('\n')[1].split('/'); var fileName = originFile[originFile.length - 1].split(':')[0]; var lineNumber = originFile[originFile.length - 1].split(':')[1]; console.log(fileName+" line "+lineNumber); } }
答案很简单。 否和否(否)。
当javascript运行的时候,源文件/ url的概念已经消失了。
也没有办法确定一个行号,因为再次执行时,代码“行”的概念在Javascript中不再有意义。
具体的实现可以提供API钩子来允许特权代码访问这些细节以进行debugging,但是这些API不会暴露给普通的标准JavaScript代码。
要确定哪一行是你必须search所有的代码占据了特定的兴趣线,并从顶部的“\ n”字符到这个感兴趣的,并添加1。
我正在写一个应用程序来做这个事情。 这是一个HTML的最佳实践validation程序,目前仍在开发中,但您感兴趣的错误输出过程已完成。