无法使用 Esprima/Acorn 解析函数:意外标记“(”

Unable to parse function with Esprima/Acorn: unexpected token '('

我可以使用 Esprima 和 Acorn 解析箭头函数,但使用普通函数会出错:

const esprima = require('esprima');
const acorn = require('acorn');

console.log(esprima.parseScript(` () => { console.log('Test')}`)); //works
console.log(acorn.parse(` () => { console.log('Test') }`); //works

console.log(esprima.parseScript(`function () { console.log('Test')}`)); // Unexpected token
console.log(acorn.parse(`function () { console.log('Test') }`); //Unexpected token

有什么建议吗?

tl;博士

如果该行以标记 function 开头,则它是 FunctionDeclaration, not a FunctionExpression. And a function declaration requires an identifier (in a FunctionExpression it is optional)。

--------

function () { console.log('Test') } 代码的编写方式使其成为 function declaration (FunctionDeclaration), not a function expression. And a function declaration expects an identifier (in a function expression it is optional)。

在 Chrome 控制台中尝试,你会得到同样的错误。

要了解,您必须查看 the grammar os ES6(更多内容见下文)。

() => {} (ArrowFunction) is always an expression (specifically, believe it or not, an AssignmentExpression).


A JavaScript, 在 ES6 中, Script is roughly a sequence of statements (StatementList, which is a sequence of StatementListItems).

一个StatementListItem is a Statement or a Declaration.

Statement or a Declaration之间,唯一可能的表达方式是 ExpressionStatement.

ExpressionStatement 只不过是一个 表达式 .

并在 Expression you find the FunctionExpression.

因为它们以相同的标记开始,我相信 FunctionDeclaration takes precedence over the FunctionExpression (the former is "less deep" down the grammar). So the parser consumes the token function an expects the FunctionDeclaration 继续,抛出错误。


消除错误

您可以添加标识符,满足 FunctionDeclaration 的要求:

console.log(esprima.parseScript(`function test() { console.log('Test')}`));
console.log(acorn.parse(`function test() { console.log('Test') }`);

但是,这又使它成为一个 FunctionDeclaration。要使您的代码单独成为一个函数表达式,如 @JaredSmith in 所指出的那样,请将其包装到 (/)s:

console.log(esprima.parseScript(`(function () { console.log('Test')} )`));
console.log(acorn.parse(`(function () { console.log('Test') } )`);