JavaScript 是否有确定当前执行语句的行号的机制(如果有,是什么)?
您可以使用:
function test(){
console.trace();
}
test();
在不同浏览器和浏览器版本之间更具可移植性(应该在 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];
}
您可以尝试解析函数的源代码来寻找一些标记。
这是一个简单的例子(是的,有点混乱)。
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;
}
将以下代码片段插入您的代码中:
console.debug("line:", /\(file:[\w\d/.-]+:([\d]+)/.exec(new Error().stack)[1]);
const line = new Error().stack.match(/(:[\d]+)/)[0].replace(':','')
console.log(line)
如果您使用node.js并且您关心获取行号的成本(可能不是最重要的事情),那么使用v8的调用点是我所知道的获取行号的最佳方法。
以下代码避免了将堆栈转换为文本的成本,并直接从
stack[1]
对象中提取调用者 (callsites
) 行号。
'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 了解文档。
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'))
*/
纯粹无法从 Error.stack 中获取行号,因为在 Angular 中,行号就是编译后代码的行号。但我们可以获取错误是在哪一种方法中产生的信息。此代码片段中的 Logger 类将此信息添加到新的日志条目中。
https://stackblitz.com/edit/angular-logger?file=src/app/Logger/logger.ts
如果您的代码是 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“字体增强”:Android 上的 Chrome 调整字体大小。将其视为每个网页都需要的样板。)
以下行只是为了验证我没有犯错误。在浏览器的调试器中查看,或者通过右键单击/保存网页,它会变成一个 HTML 注释,显示正确的源文件名和行号:
<!-- *** this is line <?php echo __LINE__ . ' of ' . basename(__FILE__); ?> *** -->
变成:
<!-- *** this is line 1234 of my_file.php *** -->
现在,无论我在哪里看到行号,无论是在错误消息中还是在 JavaScript 调试器中,它都是正确的。 PHP 行号和 JavaScript 行号始终一致且相同。