Как получить номер строки функции вызывающего JavaScript? Как получить исходный URL звонящего из JavaScript?

Я использую следующее для получения имени функции вызывающей стороны JavaScript:

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

Есть ли способ узнать номер строки, с которой был вызван метод?

Кроме того, есть ли способ получить имя файла JavaScript, из которого был вызван метод? Или исходный URL?

18 ответов

Решение

Это работает для меня в 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);

Решение kangax вводит ненужную область try..catch. Если вам нужен доступ к номеру строки чего-либо в JavaScript (если вы используете Firefox или Opera), просто получите доступ (new Error).lineNumber,

Да. Вот кросс-браузерная функция, которая использует собственные методы каждого браузера:

http://github.com/eriwen/javascript-stacktrace

[фиксированная ссылка]

Я был удивлен, что большинство из этих ответов предполагали, что вы хотите обработать ошибку, а не просто выводить полезные трассировки отладки и для обычных случаев.

Например, мне нравится использовать console.log обертка, как это:

consoleLog = function(msg) {//See https://stackru.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]

См. /questions/29300682/kak-ya-mogu-opredelit-tekuschij-nomer-stroki-v-javascript/29300690#29300690 а также надлежащую оболочку для console.log с правильным номером строки?

Я понимаю, что это старый вопрос, но теперь есть метод под названием console.trace("Message") это покажет вам номер строки и цепочку вызовов методов, которые привели к журналу вместе с сообщением, которое вы передаете. Более подробную информацию о хитростях регистрации в javascript можно найти здесь, на freecodecamp и в этом среднем посте.

Это часто достигается путем выдачи ошибки из текущего контекста; затем анализируя объект ошибки для таких свойств, как 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 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 номер строки кода (и имя файла) показывает строку (файл), которая выдает исключение "Ошибка", а не исключение "errorHandler", которое вы действительно хотите для отладки. легко. Создание собственных исключений - это замечательно, но в больших проектах их обнаружение может быть довольно сложной задачей, особенно если они имеют похожие сообщения. Итак, что вы можете сделать, это передать ссылку на фактический пустой объект Error в ваш обработчик ошибок, и эта ссылка будет содержать всю необходимую информацию (например, в Firefox вы можете получить имя файла, номер строки и т. Д.).; в chrome вы получите нечто подобное, если прочитаете свойство 'stack' экземпляра Error). Короче говоря, вы можете сделать что-то вроде этого:

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

Теперь вы можете получить фактический файл и номер строки, которая вызвала пользовательское исключение.

Вот как я это сделал, я проверял это и в 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);
    }
}

Номер строки на самом деле является чем-то статичным, поэтому, если вы просто хотите, чтобы он записывался в журнал, он мог бы быть предварительно обработан чем-то вроде gulp. Я написал небольшой плагин 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), Преимущество в том, что теперь вы можете объединять свои файлы, переносить их... и вы все равно получите строку

Если вам нужно что-то очень полное и точное, для v8 (имеется в виду NodeJS и Chrome) есть stack-trace пакет, который работал у меня:

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

У этого есть несколько преимуществ: возможность создавать глубокие трассировки стека, возможность пересекать async вызывает и предоставляет полный URL-адрес скриптов для каждого кадра стека.

Вы можете найти дополнительную информацию об API отслеживания стека v8 здесь .

Если вам нужно что-то, что работает в других браузерах, есть этот пакет:

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

Эта библиотека анализирует отформатированные строки трассировки стека, которые вы обычно видите в консоли devtools, что означает, что у нее есть доступ только к информации, которая фактически отображается в отформатированной дорожке стека - в отличие от API v8, вы не можете получить (среди прочего) полный URL-адрес скрипта в стековом фрейме.

Обратите внимание, что синтаксический анализ отформатированной трассировки стека является несколько хрупким подходом, поскольку это форматирование может измениться в браузерах, что приведет к поломке вашего приложения.

Насколько я знаю, нет более безопасной ставки на кроссбраузерность - если вам нужно что-то быстрое, точное и полное, работающее во всех браузерах, вам в значительной степени не повезло.

Если вы хотите узнать номер строки для целей отладки или только во время разработки (по той или иной причине), вы можете использовать Firebug (расширение 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);
}

Следующий код работает для меня в 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);
}
console.log(new Error);

Он покажет вам весь трек.

Мой вклад в пользовательские ошибки в JavaScript:

  1. Во-первых, я согласен с этим парнем @B T в Наследовании от объекта Error - где находится свойство сообщения?, мы должны построить его правильно (на самом деле вы должны использовать библиотеку объектов 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. затем мы должны определить глобальную функцию обработки ошибок (необязательно), или они будут в конечном итоге обработчиком:

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

Только при передаче третьего параметра как new Error() мы можем видеть стек с номерами функций и строк!

На 2 функция также может обрабатывать ошибки, выдаваемые двигателем.

Конечно, реальный вопрос в том, действительно ли нам это нужно и когда; Есть случаи (на мой взгляд, 99%), когда false достаточно и оставьте только некоторые критические точки, которые будут показаны с ошибкой.

Пример: http://jsfiddle.net/centurianii/m2sQ3/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 не определены.

Чтобы определить, в какой строке что-то находится, вы должны найти во всем коде код, который занимает конкретную интересующую строку, и подсчитать символы "\n" сверху вниз и добавить интересующий их 1.

На самом деле я делаю именно это в приложении, которое пишу. Это средство проверки соответствия рекомендациям для HTML, которое все еще находится в стадии разработки, но процесс вывода ошибок, который вас заинтересует, завершен.

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

ГЛОБАЛЬНАЯ ОБРАБОТКА ОШИБОК ДЛЯ ВСЕХ ВАШИХ 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

Ответы просты. Нет и нет (нет).

К тому времени, когда javascript запускает концепцию исходных файлов / URL-адресов, исходящие из которых исчезли.

Также нет способа определить номер строки, потому что снова к моменту исполнения понятие кода "строки" больше не имеет смысла в Javascript.

Конкретные реализации могут предоставлять хуки API, чтобы разрешить доступ привилегированного кода к таким деталям с целью отладки, но эти API не подвергаются воздействию обычного стандартного кода Javascript.

Другие вопросы по тегам