如何在JavaScript中确定当前行号?

132
JavaScript 有一种机制可以确定当前执行语句的行号吗?如果有,它是什么?

11个回答

87

var thisline = new Error().lineNumber

如果在你所使用的环境中无法工作,可以尝试:

var stack = new Error().stack

然后通过查找堆栈来获取行号。


3
不能在IE中使用,错误对象上不存在lineNumber属性,也没有stack :-)。 - Andy E
1
在IE浏览器中有一行号。我知道这是因为当我的JavaScript抛出错误时,它会显示在一个大于1亿的行号上。 - Malfist
我没有得到正确的数字,它应该是1250,但是显示为1350。 - john-jones
1
问题:如果您正在使用PHP,则JavaScript看到的“源代码”不是原始源代码,因此它具有错误的行号。(这可能是赫尔曼遇到的问题。)有人知道如何使JavaScript看到原始的PHP源代码行号吗?解决方案可能涉及某种“源映射”生成,但我找不到如何做到这一点。这肯定是一个已解决的问题,对吧? - Dave Burton
注意:有时在构造Error对象时,堆栈/行号可能不可用,只有在抛出时才可用,例如在Google Apps Script中 - 在这种情况下,请参见此答案以获取解决方案。 - user202729
1
我认为.lineNumber只在Firefox中有效。 - kurdtpage

59

您可以使用:

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

test();

2
到目前为止,最简单的解决方案,甚至可以在MS Edge上使用。 - Danger
它提供了与Firefox控制台相同的数字,例如执行行而不是代码行。 - Mbotet

35

在不同浏览器和浏览器版本之间更加可移植(应该可以在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];
}

谢谢。我根据您的建议修改了这个:https://dev59.com/-HM_5IYBdhLWcg3whznx#37081135 - Ryan
3
如果你调整正则表达式,你可以返回行号和列号:var frameRE = /:(\d+:\d+)[^\d]*$/; 这样会更有用,特别是当JS被压缩成一行时。 - Quinn Comendant
警告,不适用于Chrome的ViolentMonkey脚本 - 你会得到一个虚假的数字,不知道为什么。 - hanshenrik
也许是有趣的提示。这适用于0ad模组(版本0.0.26)。 - SL5net

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

2

将以下代码片段注入到您的代码中:

console.debug("line:", /\(file:[\w\d/.-]+:([\d]+)/.exec(new Error().stack)[1]);

必要时更换协议名称(例如“http:”)。 - crishushu
4
我无法使其运作。我得到了 TypeError: /\(http:[\w\d/.-]+:([\d]+)/.exec(...) is null 的错误信息。 - Ryan

1

你可以尝试:

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

在你想知道的地方抛出一个错误(虽然不是非常理想,但如果你正在调试可能会有所帮助)。

注意:WebKitOpera中未定义/处理window.onerror(截至我上次检查时)。


1
请注意,window.onerror在webkit中不起作用:https://bugs.webkit.org/show_bug.cgi?id=8519 - Annie
1
有趣的是,你甚至可以创建一个特殊的函数 throwAndResume(resumeFunction);,它将存储 resumeFunction,抛出错误,在错误处理程序中记录详细信息,然后调用 resumeFunction 来继续你的程序。 - Mark Bolusmjak

1
const line = new Error().stack.match(/(:[\d]+)/)[0].replace(':','')
console.log(line)

1
如果你正在使用node.js并且关心获取行号的成本(不太可能是最重要的事情),那么使用v8的callsites是我知道的最好的获取行号的方法。
以下代码避免了将堆栈转换为文本的成本,并直接从callsites对象中提取调用者(stack [1])的行号。
  'use strict';

  function thisLine() {
    let line;
    const _prepareStackTrace = Error.prepareStackTrace;
    Error.prepareStackTrace = (_, stack) => {
      line = stack[1].getLineNumber();
    };
    const e = new Error();
    e.stack;
    Error.prepareStackTrace = _prepareStackTrace;

    return line;
  }

  if (require.main === module) {
    console.log('this line is', thisLine());
  }

请参考 https://v8.dev/docs/stack-trace-api 获取文档。

0

来源:git @tiagofrancafernandes


var getPos = (toGet = null) => {
    let stack = String(new Error().stack);
    let calledFrom = String((stack.split(`\n`)).filter(item => item).at(-1));
    calledFrom = calledFrom.startsWith('@') ? calledFrom.slice(1) : calledFrom;

    let items = {
        stack: stack,
        calledFrom: calledFrom,
    }

    let lineCol = String(calledFrom).match(/(\:)([0-9]){1,}(:([0-9]).?)$/g)[0];
    lineCol = String(lineCol).split(':').filter(item => item)
    items['lineCol'] = lineCol.join(':');
    items['line'] = lineCol.length == 2 ? lineCol[0] : null;
    items['col'] = lineCol.length == 2 ? lineCol[1] : null;

    toGet = toGet ? String(toGet) : null;

    if (toGet && !Object.keys(items).includes(toGet)) {
        return null;
    }

    return items[`${toGet}`] ?? items;
}

var __LINE__ = () => getPos('line');

// Usage
/*
    console.log(getPos())
    console.log(__LINE__())
    console.log(getPos('lineCol'))
    console.log(getPos('line'))
    console.log(getPos('col'))
    console.log(getPos('calledFrom'))
    console.log(getPos('stack'))
*/

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接