Как я могу определить текущий номер строки в JavaScript?

96

Есть ли в JavaScript механизм для определения номера строки выполняемого в данный момент оператора (и если да, то какой)?

Мэтью Мердок
источник

Ответы:

69

var thisline = new Error().lineNumber

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

var stack = new Error().stack

Затем найдите в стеке номер строки.

z5h
источник
3
Не будет работать в IE, lineNumberсвойство не существует для объектов ошибок. И тоже stack:-)
Andy E
1
где-то в IE есть номер строки. Я знаю это, потому что, когда мой javascript выдает ошибку, он говорит, что он находится в строке с числом больше 100 миллионов.
Malfist
Я не совсем понимаю правильное число, его 1350, тогда как должно быть 1250.
Fzs2,
1
Проблема: если вы используете PHP, «исходный код», видимый javascript, не является исходным исходным кодом, поэтому в нем неправильные номера строк. (Вероятно, именно это и происходит с Германом.) Кто-нибудь знает, как заставить javascript видеть исходные номера строк исходного кода PHP? Решение, вероятно, включает в себя создание какой-то «исходной карты», но я не могу найти, как это сделать. Неужели это решенная проблема?
Дэйв Бертон
Примечание: иногда номер стека / строки недоступен при создании объекта Error, только когда он создается, например, в скрипте Google Apps - в этом случае см. Этот ответ для решения.
user202729 02
38

Ты можешь использовать:

function test(){
    console.trace();
}

test();
Baligena
источник
1
Безусловно, самое простое решение, и оно работает даже на MS Edge.
Danger
27

Немного более портативно между разными браузерами и версиями браузеров (должно работать в Firefox, Chrome и IE10 +):

function ln() {
  var e = new Error();
  if (!e.stack) try {
    // IE requires the Error to actually be throw 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/);
  // We want our caller's frame. It's index into |stack| depends on the
  // browser and browser version, so we need to search for the second frame:
  var frameRE = /:(\d+):(?:\d+)[^\d]*$/;
  do {
    var frame = stack.shift();
  } while (!frameRE.exec(frame) && stack.length);
  return frameRE.exec(stack.shift())[1];
}
Джватт
источник
Спасибо. Я адаптировал ваше предложение к этому: stackoverflow.com/a/37081135/470749
Райан
1
Если вы настроите регулярное выражение, вы можете возвращать номера строк и столбцов: var frameRE = /:(\d+:\d+)[^\d]*$/;что намного полезнее, особенно когда JS минимизирован в одну длинную строку.
Куинн Комендант
Предупреждение, не работает в скриптах ViolentMonkey для Chrome - вы получите фальшивый номер, не знаю почему.
hanshenrik
5

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

function foo()  
{       
    alert(line(1));
    var a;
    var b;      
    alert(line(2));
}   
foo();

function line(mark)
{
    var token = 'line\\(' + mark + '\\)';       
    var m = line.caller.toString().match(
        new RegExp('(^(?!.*' + token + '))|(' + token + ')', 'gm')) || [];
    var i = 0;
    for (; i < m.length; i++) if (m[i]) break;
    return i + 1;
}
Михаил Насыров
источник
3

Добавьте в код следующий фрагмент:

console.debug("line:", /\(file:[\w\d/.-]+:([\d]+)/.exec(new Error().stack)[1]);
Crishushu
источник
при необходимости замените имя протокола (например, "http:")
crishushu
1
Я не мог заставить это работать. Я понимаю TypeError: /\(http:[\w\d/.-]+:([\d]+)/.exec(...) is null.
Райан
2

Можешь попробовать:

window.onerror = handleError;
function handleError(err, url, line){
    alert(err + '\n on page: ' + url + '\n on line: ' + line);
}

Затем выдайте ошибку там, где вы хотите знать (не слишком желательно, но это может помочь вам, если вы отлаживаете.

Примечание: window.onerrorне определяется / не обрабатывается в WebKit или Opera (в последний раз, когда я проверял)

Scunliffe
источник
1
Обратите внимание, что window.onerror не работает в webkit: bugs.webkit.org/show_bug.cgi?id=8519
Энни,
1
Интересно. Вы даже можете создать специальную функцию throwAndResume(resumeFunction);, которая сохраняла бы функцию resumeFunction, выдавала ошибку, и в вашем обработчике ошибок записывала детали, а затем вызывала resumeFunction для продолжения вашей программы.
z5h
0

Чисто невозможно получить номер строки из Error.stack, потому что в Angular номер строки - это номер строки скомпилированного кода. Но можно узнать, каким методом возникла ошибка. Класс Logger в этом фрагменте кода добавляет эту информацию в новую запись журнала.

https://stackblitz.com/edit/angular-logger?file=src/app/Logger/logger.ts

Вири
источник
-2

Если ваш код - JavaScript + PHP, то текущий номер строки PHP доступен в JavaScript как буквальная константа, потому что он доступен в PHP как   <?= __LINE__ ?>

(Это при условии, что у вас включены короткие теги PHP, очевидно.)

Так, например, в JavaScript вы можете сказать:

this_php_line_number = <?= __LINE__ ?>;

Однако, если вы не будете осторожны, номер строки PHP может отличаться от номера строки JavaScript, потому что PHP «съедает» исходные строки еще до того, как браузер их увидит. Таким образом, проблема заключается в том, чтобы убедиться, что номера строк PHP и JavaScript совпадают. Если они разные, использование отладчика JavaScript в браузере становится менее приятным.

Вы можете убедиться, что номера строк совпадают, включив оператор PHP, который записывает правильное количество новых строк, необходимых для синхронизации номеров строк на стороне сервера (PHP) и на стороне браузера (JavaScript).

Вот как выглядит мой код:

<!DOCTYPE html>
<html lang="en">
<!-- Copyright 2016, 2017, me and my web site -->
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, user-scalable=yes">

<?php

...lots of PHP stuff here, including all PHP function definitions ...

echo str_repeat("\n",__LINE__-6); # Synchronize PHP and JavaScript line numbers
?>
<!-- *** this is line <?php echo __LINE__ . ' of ' . basename(__FILE__); ?> *** -->

  <title>My web page title</title>

...lots of HTML and JavaScript stuff here...

</body>
</html>
<!-- *** this is line <?php echo __LINE__ . ' of ' . basename(__FILE__); ?> *** -->

Ключевым моментом является этот оператор PHP:

echo str_repeat("\n",__LINE__-6);

Это выводит достаточно новых строк, чтобы номер строки, видимый JavaScript, совпадал с номером строки PHP. Все определения функций PHP и т. Д. Находятся вверху, перед этой строкой.

После этой строки я ограничиваю использование PHP кодом, который не меняет номера строк.

«-6» учитывает тот факт, что мой PHP-код начинается со строки 8. Если вы запустите свой PHP-код раньше, вы уменьшите это число. Некоторые люди ставят свой PHP на самый верх, даже перед DOCTYPE.

(Строка мета-области просмотра отключает «усиление шрифта» Android Chrome в соответствии с этими вопросами и ответами по переполнению стека: Chrome на Android изменяет размер шрифта . Считайте это шаблоном, который нужен каждой веб-странице.)

Следующая строка предназначена только для проверки того, что я не ошибся. При просмотре в отладчике браузера или при щелчке правой кнопкой мыши / сохранении веб-страницы он становится комментарием HTML, который показывает правильное имя исходного файла и номер строки:

<!-- *** this is line <?php echo __LINE__ . ' of ' . basename(__FILE__); ?> *** -->

становится:

<!-- *** this is line 1234 of my_file.php *** -->

Теперь, когда я вижу номер строки, будь то сообщение об ошибке или отладчик JavaScript, он правильный. Номера строк PHP и номера строк JavaScript всегда согласованы и идентичны.

Дэйв Бертон
источник