如何获取JavaScript调用者函数行号?如何获取JavaScript调用者源URL?

时间:2009-08-27 12:49:07

标签: javascript

我使用以下内容获取JavaScript调用者函数名称:

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

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

另外,有没有办法获取调用该方法的JavaScript文件的名称?或源URL?

16 个答案:

答案 0 :(得分:89)

这适用于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);

答案 1 :(得分:23)

kangax的解决方案引入了不必要的try..catch范围。如果您需要访问JavaScript中的某些行号(只要您使用的是Firefox或Opera),只需访问(new Error).lineNumber

答案 2 :(得分:8)

我很惊讶大多数这些答案都假设你想要处理错误,而不仅仅是为正常情况输出有用的调试跟踪。

例如,我喜欢使用这样的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/以及A proper wrapper for console.log with correct line number?

答案 3 :(得分:4)

这通常是通过从当前上下文中抛出错误来实现的;然后分析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第3版中出现过)。

还要记住,函数反编译被指定为依赖于实现,因此可能会产生非常意外的结果。我写了herehere

答案 4 :(得分:3)

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

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'异常的行(文件)而不是你真正想要的'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();
}

现在您可以获得引发自定义异常的实际文件和行号。

答案 5 :(得分:3)

行号实际上是静态的,所以如果您只是想要它进行日志记录,那么它可以像gulp一样进行预处理。我写了一个小小的gulp plugin就是这样做的:

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)。优点是,现在您可以连接文件,转换它们......然后您仍然可以获得该行

答案 6 :(得分:2)

如果您想知道用于调试目的的行号,或仅在开发期间(出于某种原因),您可以使用Firebug(Firefox扩展名)和throw例外。

修改

如果您确实需要在生产中出于某种原因这样做,您可以预处理您的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);
}

答案 7 :(得分:1)

以下是我根据此论坛上的信息撰写的内容:

这是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为undefined。

答案 8 :(得分:1)

以下代码适用于Mozilla和Chrome。

其日志功能,显示文件的名称和调用者的行。

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);
}

答案 9 :(得分:1)

我对JavaScript中自定义错误的贡献:

  1. 首先,我同意Inheriting from the Error object - where is the message property?的这个@BT家伙,我们必须正确构建它(实际上你必须使用js对象库,我最喜欢的:https://github.com/jiem/my-class):< / p>

    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. 然后,我们应该定义一个全局错误处理函数(可选),或者它们最终会导致引擎:

    window.onerror = printError; 
    function printError(msg, url, line){
        document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line;
        return true;
    }
    
  3. 最后,我们应该谨慎地抛出自定义错误:

    //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());
    
  4. 仅在将第三个参数作为new Error()传递时,我们能够看到具有函数和行号的堆栈!

    在2处,该函数也可以处理引擎引发的错误。

    当然,真正的问题是我们真的需要它吗?有些情况(我认为是99%),false的优雅回报就足够了,只留下一些关键点,以便抛出错误。

    示例:http://jsfiddle.net/centurianii/m2sQ3/1/

答案 10 :(得分:1)

我就是这样做的,我已经在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);
    }
}

答案 11 :(得分:1)

我意识到这是一个古老的问题,但是现在有一个名为console.trace("Message")的方法,它将向您显示行号和导致日志的方法调用链以及您传递的消息。 here at freecodecampthis medium blog post

提供了有关javascript记录技巧的更多信息。

答案 12 :(得分:1)

所有 JS 代码的全局错误句柄

window.onerror = function (msg, url, lineNo, columnNo, error) {
            // ... handle error ...
            alert(msg + ' - ' + url + ' - ' + lineNo + ' - ' + columnNo);
            return false;
        }

适用于所有浏览器:)
对于简单的测试,将此错误代码行添加到您的 js 的任何部分:

aa.ll.kk;//to fire a pure syntax error

答案 13 :(得分:0)

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

当javascript运行时,源文件/网址的概念已经消失了。

也无法确定行号,因为在执行时,代码“行”的概念在Javascript中不再有意义。

特定实现可以提供API挂钩,以允许特权代码访问此类详细信息以进行调试,但这些API不会暴露给普通的标准Javascript代码。

答案 14 :(得分:0)

要确定某个行是什么,您必须搜索占用特定兴趣行的代码的所有代码,并计算从顶部到此感兴趣的“\ n”字符并添加1.

我实际上是在我正在编写的应用程序中执行此操作。它是HTML的最佳实践验证器,并且仍处于开发阶段,但您感兴趣的错误输出过程已经完成。

http://mailmarkup.org/htmlint/htmlint.html

答案 15 :(得分:0)

console.log(new Error);

它将显示整个曲目。