当使用new Function(params,body)构造函数从JavaScript代码创建新函数时,在body中传递无效字符串会产生SyntaxError。而此异常包含错误消息(即:Unexpected token =
),但似乎不包含上下文(即。行/列或发现错误的字符)。
小提琴示例:https://jsfiddle.net/gheh1m8p/
var testWithSyntaxError = "{\n\n\n=2;}";
try {
var f=new Function('',testWithSyntaxError);
} catch(e) {
console.log(e instanceof SyntaxError);
console.log(e.message);
console.log(e.name);
console.log(e.fileName);
console.log(e.lineNumber);
console.log(e.columnNumber);
console.log(e.stack);
}
输出:
true
(index):54 Unexpected token =
(index):55 SyntaxError
(index):56 undefined
(index):57 undefined
(index):58 undefined
(index):59 SyntaxError: Unexpected token =
at Function (native)
at window.onload (https://fiddle.jshell.net/_display/:51:8)
**如何在不使用外部依赖项的情况下,在传入的字符串中确定SyntaxError的位置?**我需要浏览器和nodejs的解决方案。
请注意:我确实有一个使用eval-equivalent代码的正当理由。
4条答案
按热度按时间798qvoo81#
在基于Chromium的浏览器中,正如您所看到的,在V8解析代码(在实际运行之前)时抛出SyntaxError的东西周围放置
try
/catch
不会产生任何有用的东西;它将描述在堆栈跟踪中 * 导致有问题的脚本的评估 * 的行,但没有关于问题在所述脚本中的位置的细节。但是,有一个跨浏览器的解决方案。不使用
try
/catch
,您可以将error
侦听器添加到window
,提供给回调的第一个参数将是ErrorEvent
,它具有有用的lineno
和colno
属性:在浏览器控制台中检查结果:
这就是我们想要的!20号字符对应于
而字符5对应于
不过,有几个问题:最好确保在
error
中监听的是运行checkSyntax
时抛出的错误。此外,try
/catch
* 可以 * 用于运行时错误(包括语法错误)* 在 * 脚本文本已被解释器解析为AST之后。因此,您可以让checkSyntax
only 检查JavaScript最初是否可解析,而不检查其他内容,然后 * 使用try/catch
(如果您想真实的运行代码)来捕获运行时错误。您可以通过将throw new Error
插入到eval
ed文本的顶部来实现此操作。这里有一个方便的基于Promise的函数可以实现这一点:
结果:
如果在
window
上抛出错误是一个问题(例如,如果其他东西已经在监听窗口错误,而你不想打扰它,并且你不能先附加你的监听器并在事件上调用stopImmediatePropagation()
),另一个选择是使用web worker,它有自己的执行上下文,与原始的window
完全分离:本质上,
checkSyntax
所做的是检查所提供的代码是否可以被当前解释器 * 解析为Abstract Syntax Tree *。你也可以使用像@babel/parser或acorn这样的包来尝试解析字符串,尽管你必须根据当前环境中允许的语法来配置它(随着新语法的添加,它会发生变化)。以上适用于 * 浏览器 *。在Node中,情况有所不同:侦听uncaughtException不能用于拦截语法错误的详细信息,AFAIK。但是,您可以使用vm模块来尝试编译代码,如果它在运行之前抛出SyntaxError,您将看到类似于下面的内容。跑步
导致一堆
因此,只需查看堆栈中的第一项即可获得行号,并查看
^
之前的空格数即可获得列号。使用与前面类似的技术,如果解析成功,则在第一行抛出错误:结果:
上面写着:
我如何在不使用外部依赖项的情况下,在传入的字符串中精确定位SyntaxError位置?我需要浏览器和nodejs的解决方案。
除非您必须在没有外部库的情况下实现这一点,否则使用库确实是最简单(并且经过测试)的解决方案。如前所述,Acorn(和其他解析器)也可以在Node中工作。
wz3gfoph2#
我总结了一些评论和其他研究:
简单回答:目前不可能
目前还没有跨平台的方法从
new Function()
或eval()
调用中检索语法错误位置。部分解
error.lineNumber
和error.e.columnNumber
。如果错误的位置不是关键的,则这可以与特征检测一起使用。1.使用基于JSLint或PEG.js的单独javascript解析器。
1.为作业编写自定义javascript解析器。
解决方案1和2不完整,依赖于不属于标准的功能。如果这些信息是一种帮助,而不是一种要求,它们可能是合适的。
解决方案3依赖于外部代码库,这是原始问题明确要求的。如果需要此信息并且较大的代码库是可接受的折衷,则它是合适的。
解决方案4不切实际。
Credits:@user3896470,@ivan-kuckir,@aprillion
5cnsuln73#
浏览器解决方案:
您可以使用最新的Firefox来获取所需的信息,如错误行号和字符串中的列号。
示例:
Firefox控制台中的输出:
其中6是行号,1是字符串中错误的列号。
在Chrome中无法使用。有关于此问题的chrome浏览器的错误。参见:
https://bugs.chromium.org/p/v8/issues/detail?id=1281
https://bugs.chromium.org/p/v8/issues/detail?id=1914
https://bugs.chromium.org/p/v8/issues/detail?id=2589
i5desfxk4#
这是一个启发式的近似方法,但是可以对部分代码调用
Function()
构造函数(只是为了解析,而不是运行),以查看SyntaxError是否仍然存在。看起来反复从结尾删除线条大多有效。这容易添加新的语法错误-例如可以启动代码块{...并且不完成...}它们-但是通常解析器保持报告最早的错误。只有当您删除最初有问题的行时,错误才会改变/消失。
Function()
构造函数的注意事项:它插入function anonymous(arg1, arg2
作为线1,和
) {
作为第2行(参见.toString()成功解析的函数)。这将使所有行号偏移2!下面的代码补偿了SyntaxError,但对于任何非语法异常,它将影响
.stack
跟踪中的数字-这些我没有尝试纠正。