首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在计算命名函数时,Java 11中的Nashorn与Java 8的行为不同

在计算命名函数时,Java 11中的Nashorn与Java 8的行为不同
EN

Stack Overflow用户
提问于 2020-06-21 15:51:20
回答 1查看 854关注 0票数 15

我有一个Java应用程序,它允许用户通过定义JavaScript函数在运行时操纵某些对象。我们目前正在使用Java 8中的Nashorn进行此操作,但我们希望迁移到Java 11。一旦我们使用了Java 11,我们将能够使用GraalVM提供此功能,但目前我们需要维护Java8 -> Java 11升级的兼容性。

在Java 11中,当我们使用Nashorn函数时,该函数的行为似乎有所不同,这取决于该函数是否命名,Java 8中的情况并非如此。

代码语言:javascript
复制
$ jjs -v
nashorn 11.0.6
Warning: The jjs tool is planned to be removed from a future JDK release
jjs> function foo() {}
jjs> function () {}
function () {}

注意,第一个函数定义不返回任何内容。在Java 8中,即使在函数命名时,它也返回该函数:

代码语言:javascript
复制
$ jjs -v
nashorn 1.8.0_252
jjs> function foo() {}
function foo() {}

我们当前调用这些脚本的方式是:

代码语言:javascript
复制
CompiledScript compiled = scriptEngine.compile(userProvidedScript);
Object evaled = compiled.eval(bindings);
scriptEngine.invokeMethod(evaled, "call", evaled, ... input parameters ...)

好奇是否有人知道这件事的根本原因和任何好的解决办法?出于后台原因,我需要支持function(...)function foo(...)。由于这是在我们的Java应用程序中完成的,因此我们可能会以某种方式包装用户提供的脚本,或者尝试从绑定中获取脚本(这看起来很容易出错,因为可以定义多个脚本,Java 8的行为将用于调用最后定义的脚本)。

EN

回答 1

Stack Overflow用户

发布于 2022-02-16 06:12:35

可能是由于纳什霍恩的匿名函数语句的自定义特性(实际上称为"函数声明")出现问题,也不小心也适用于实际命名的函数声明。因为在纳什霍恩的文档中没有描述过这一点,所以我想他们不想要这种行为,于是就把它处理掉了。

解决方案:

转换源代码,以便作为它的最后一步,它将产生由您上次命名的函数声明定义的函数对象。

考虑一下我的测试,看看这在OpenJDK 8和11中是可行的:

nashorn @ 1.8.0_302:

代码语言:javascript
复制
jjs> function bar() { foo(); }; function foo() { bar(); }     
function foo() { bar(); }

jjs> function bar() { foo(); }; function foo() { bar(); }; foo
function foo() { bar(); }

nashorn @ 11.0.6:

代码语言:javascript
复制
jjs> function bar() { foo(); }; function foo() { bar(); }

jjs> function bar() { foo(); }; function foo() { bar(); }; foo
function foo() { bar(); }

为了弄清楚要使用什么名称,您应该能够解析JS并使用套餐处理它的AST。

树访问者/函数名累加器看起来可能如下所示:

代码语言:javascript
复制
private static class FuncDeclarationVisitor extends SimpleTreeVisitorES5_1<Void, Void> {
    public String lastFunctionName = null;

    @Override
    public Void visitFunctionDeclaration(FunctionDeclarationTree node, Void param) {
        // Anonymous function declaration ==> null
        IdentifierTree functionName = node.getName();
        lastFunctionName = functionName != null ? functionName.getName() : null;
        return super.visitFunctionDeclaration(node, param);
    }
}

您可以调用它,就像:

代码语言:javascript
复制
CompilationUnitTree parsedTree;     // Use Parser's parse method

FuncDeclarationVisitor visitor = new FuncDeclarationVisitor();
parsedTree.accept(visitor);

return visitor.lastFunctionName;     // Null if the last function declaration was anonymous

但我不认为有任何方法可以修改AST,然后将其发送到NashornScriptEngine的编译器,您可能需要向源文本本身添加一些内容()。

此外,您还可能希望访问者检测到其他类型的节点,这些节点不是函数声明,这样您就不会意外地转换脚本并打击可能产生的其他表达式(非函数)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62500957

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档