如何得到 JavaScript 调用方函数的行号和调用方源 URL

我使用以下方法获取 JavaScript 调用方函数名:

var callerFunc = arguments.callee.caller.toString();
callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous")

有没有办法发现调用该方法的行号?

另外,是否有一种方法可以获得从中调用该方法的 JavaScript 文件的名称?或者源 URL?

132551 次浏览

答案很简单,不和不(不)。

当 javascript 运行源文件/url 的概念时,come 已经不存在了。

也没有办法确定一个行号,因为在执行的时候,代码“ lines”的概念在 Javascript 中已经没有意义了。

特定的实现可以提供 API 钩子,允许特权代码访问这些细节,以便进行调试,但是这些 API 不会暴露给普通的标准 Javascript 代码。

要确定某个东西在哪一行上,您必须搜索占据特定行的所有代码,并从顶部开始计数“ n”字符,然后添加1。

实际上,我正在编写一个应用程序来做这件事。它是 HTML 的最佳实践验证器,目前仍在大量开发中,但您感兴趣的错误输出过程已经完成。

Http://mailmarkup.org/htmlint/htmlint.html

如果出于调试的目的,或者仅在开发期间(出于某种原因) ,您想知道行号,那么可以使用 纵火犯(Firefox 扩展)和 作为异常。

编辑 :

如果出于某种原因,在生产环境中确实需要这样做,那么可以对 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);
}

这通常是通过从当前上下文抛出错误来实现的; 然后分析属性(如 lineNumberfileName)的错误对象(一些浏览器有这样的属性)

function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}


var err = getErrorObject();


err.fileName;
err.lineNumber; // or `err.line` in WebKit

不要忘记 callee.caller属性已被弃用(并且从来没有真正在 ECMA 第三版中出现过)。

还要记住,函数反编译被指定为与实现相关,因此可能会产生非常意外的结果。我写的是 给你给你

Kangax 的解决方案引入了不必要的尝试。.捕捉范围捕捉范围。如果您需要访问 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);

看起来我有点迟到了:) ,但是这个讨论非常有趣,所以。.假设您想要构建一个错误处理程序,并且您正在使用您自己的异常处理程序类,比如:

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 文件中。

您会注意到,在 firefox 或 chrome 的错误控制台中,显示的代码行号(和文件名)是引发‘ Error’异常的行(file) ,而不是为了简化调试而真正需要的‘ errorHandler’异常。抛出自己的异常非常好,但是在大型项目中定位它们可能是一个相当大的问题,特别是如果它们具有类似的消息。所以,你可以做的就是将一个对一个实际的空的 Error 对象的引用传递给你的错误处理器,这个引用将包含你想要的所有信息(例如在 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();
}

现在您可以得到抛出自定义异常的实际文件和行号。

下面是我根据在这个论坛上找到的信息写的:

这是 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 报告 fileName 和 lineNumber 为未定义的情况很有用。

以下代码适用于 Mozilla 和 Chrome。

它的 log 函数,显示文件名和调用者的行。

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 中自定义错误的贡献:

  1. 首先,我同意 从 Error 对象继承-消息属性在哪里?中这个@B T 的观点,我们必须正确地构建它(实际上你必须使用一个 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;
    
  2. then, we should define a global error handling function (optional) or, they'll end up to the engine:

    window.onerror = printError;
    function printError(msg, url, line){
    document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line;
    return true;
    }
    
  3. finally, we should throw our custom errors carefully:

    //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());
    

Only, when passing the third parameter as new Error() we are able to see the stack with function and line numbers!

At 2, the function can also handle error thrown by the engine as well.

Of course, the real question is if we really need it and when; there are cases (99% in my opinion) where a graceful return of false is enough and leave only some critical points to be shown with the thrown of an error.

Example: http://jsfiddle.net/centurianii/m2sQ3/1/

令我感到惊讶的是,大多数答案都假定您希望处理错误,而不仅仅是为普通情况输出有用的调试跟踪。

例如,我喜欢像这样使用 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 的正确包装器?

行号实际上是某种静态的东西,所以如果您只想将它用于日志记录,那么可以使用 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)。好处是现在你可以连接你的文件,传输它们... 你仍然可以得到线

我是这样做的,我已经在 Firefox 和 Chrome 中测试过了。这样就可以检查调用函数的位置的文件名和行号。

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);
}
}
console.log(new Error);

它会告诉你整个轨道。

我知道这是一个老问题,但是现在有一个称为 console.trace("Message")的方法,它将显示行号和导致日志的方法调用链以及您传递给它的消息。关于 javascript 日志记录技巧的更多信息可以在 在自由生态营这篇中等质量的博客文章中找到

以前是 更容易,但是在 这次浏览器更新:

这是安全的多浏览器解决方案

<!DOCTYPE html>
<html lang="en">
<head>
<script>
var lastErr;
function errHand(e) {
lastErr = e;
switch (e.target.nodeName) {
case 'SCRIPT':
alert('script not found: ' + e.srcElement.src);
break;
case 'LINK':
alert('css not found: ' + e.srcElement.href);
}
return false;
}
window.onerror = function (msg, url, lineNo, columnNo, error) {
alert(msg + ' - ' + url + ' - ' + lineNo + ' - ' + columnNo);
return false;
}
</script>
<script src="http://22.com/k.js" onerror="errHand(event)"></script>
<link rel="stylesheet" href="http://22.com/k.css" onerror="errHand(event)" type="text/css" />
</head>
<body>
<script>
not_exist_function();
</script>
</body>
</html>
  1. 不要尝试 重写或通过浏览器读取 控制台自动生成的错误日志,此时无法工作,但在 过去中发生了
  2. 为了控制装载每个 外部链接的 css/js/etc,使用 一个错误事件属性 内部标签
  3. 对于控件内联/加载 剧本,使用 一个错误
  4. 在 html 代码的 头儿中放置错误处理函数
  5. 要为其他特殊标记(如“ include”)开发此代码,可以设置 一个错误内联事件(如 第二步) ,并在 开火错误之后使用 Log (lastErr)查看错误对象字段
  6. 如果在 附件 J文件的源代码中有一个错误,那么当 js 拥有带有主 html 文件的 同源宿主时,一个错误获取完整的日志,如果在没有主机的 本地上测试这种情况,那么日志 没有就是 完整,因为 本地无主机环境不知道同一个源代码
  7. 对于发送像 阿贾克斯/网络插座这样的 请求错误处理,最好使用它们的 内置的错误处理函数

全局错误处理解决方案

process.on('uncaughtException', function (err) {
console.error('uncaughtException:\n' + err.stack + '\n');
})

这是 非常有用,因为它会显示你的错误,即 存在但不 休息你的主程序进程。

如果你需要一些非常完整和准确的东西,对于 v8(意味着 NodeJS 和 Chrome) ,有一个 stack-trace软件包,它对我很有用:

Https://www.npmjs.com/package/stack-trace

这有几个优点: 能够产生深度堆栈跟踪,能够遍历 async调用,并在每个堆栈帧上提供脚本的完整 URL。

您可以找到关于 v8堆栈跟踪 API 给你的更多信息。

如果你需要一些能在更多浏览器上工作的东西, 有这样一个软件包:

Https://www.npmjs.com/package/stacktrace-js

这个库解析了在 devtools 控制台中常见的格式化堆栈跟踪字符串,这意味着它只能访问实际出现在格式化堆栈跟踪中的信息——与 v8 API 不同的是,您无法在堆栈框架中获得(除其他外)脚本的完整 URL。

请注意,解析格式化的堆栈跟踪是一种有点脆弱的方法,因为这种格式可能会在浏览器中发生变化,从而破坏您的应用程序。

据我所知,跨浏览器的东西没有更安全的赌注-如果你需要一些快速,准确和完整的工作在所有的浏览器,你很不走运。