【问题标题】:Optional chaining (?.) in nashornnashorn 中的可选链接 (?.)
【发布时间】:2021-01-20 12:24:51
【问题描述】:

我在我的项目中使用 nashorn。我想从 json 中获取属性,但属性可能没有价值。

在javascript中,如果属性为null,则使用可选链接并设置一个值;但在 nashorn 中,当我使用 (?.) 时,出现此错误:

import org.springframework.stereotype.Service
import javax.script.ScriptEngineManager
import javax.script.Bindings

@Service
class SampleService {

    class Person(
            val firstName: String,
            val lastName: String,
            val child: Child?
    )

    class Child(
            val name: String,
            val age: Int
    )

    fun runScript() {
        val engine = ScriptEngineManager().getEngineByName("nashorn")
        val bindings: Bindings = engine.createBindings()
        val person = Person("John", "Smite", null)
        bindings["person"] = person
        try {
            val script = """
               var childAge = person.child?.age ?? 0;
               childAge; //return as result.
            """.trimIndent()
            val scriptResult: Any = engine.eval(script, bindings)
        } catch (e: Exception) {
            throw e
        }

    }
}

我收到此错误:

javax.script.ScriptException: <eval>:1:28 Expected an operand but found .
var childAge = person.child?.age ?? 0;
^ in <eval> at line number 1 at column number 28

我检查了这个链接,但我无法解决问题: Optional chaining (?.)

我该如何解决这个错误?

【问题讨论】:

  • 我不认为?: 是有效的 JS 语法。
  • json?.id ?: 'value if null' 不是有效的 JavaScript 语法;你应该得到一个语法错误,而不是运行时错误。你的意思是json?.id ?? 'value if null'? (例如,将可选链接与无效合并相结合。)另外,如果您正在编写现代 JavaScript(就像您看起来那样),请不要使用 var,使用 letconst
  • 您可以在 nashorn 中混合语言吗?这个问题中的代码是 Java 还是 JavaScript?
  • 嗯,你知道 Nashorn 支持可选链吗?这是相当新的。 (但如果没有,我希望再次出现语法错误,而不是使用 null 的属性的错误。)请用 minimal reproducible example 更新您的问题以证明问题:A Java 类(完成imports) 尝试通过 Nashorn 运行您的 JavaScript 代码,有人可以复制并粘贴到他们机器上的文件中,以准确复制您在问题中引用的错误。
  • 感谢@evolutionxbox。 mgh - 我对 Nashorn 了解不多,但我从 the WP page 注意到它声称支持“ECMAScript 5.1”(所以:真的过时了),并且它在 JDK 11 中已被弃用,并将从 JDK 中删除15 日起。因此,可能没有任何版本的 Nashorn 支持可选链接(或任何其他模糊的最新版本)。你可以使用 ES5 级别的代码 var childAge = person.child &amp;&amp; person.child.age || 0;,或者升级并使用 Nashorn 替换 GraalVM

标签: javascript java kotlin nashorn


【解决方案1】:

目前 Nashorn 的策略是遵循 ECMAScript 规范。当我们使用 JDK 8 发布时,我们将与 ECMAScript 5.1 保持一致。link

Nashorn 引擎作为 JEP 335 的一部分在 JDK 11 中已被弃用,并计划作为 JEP 372 的一部分从未来的 JDK 版本中删除。

GraalVM JavaScript 可以替代之前在 Nashorn 引擎上执行的代码。它提供了所有 以前由 Nashorn 提供的功能,其中许多功能由 默认,一些在标志后面,一些需要对你的 源代码。link

可选链非常新,ECMAScript 5.1 不支持此功能。

我从 nashorn 迁移到 GraalVM JavaScript 并更改代码如下:

import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine
import org.graalvm.polyglot.Context
import org.graalvm.polyglot.HostAccess
import org.springframework.stereotype.Service
import javax.script.ScriptEngine


@Service
class SampleService {

    data class Person(
            val firstName: String,
            val lastName: String,
            val child: Child?
    )

    data class Child(
            val name: String,
            val age: Int
    )

    fun runScript() {

        val person = Person("John", "Smite", null)

        val engine: ScriptEngine = GraalJSScriptEngine.create(null,
                Context.newBuilder("js")
                        .allowHostAccess(HostAccess.ALL)
                        .allowExperimentalOptions(true)
                        .option("js.ecmascript-version", "2020")
                        .option("js.nashorn-compat", "true"))
        engine.put("person", person)
        try {
            val script = """
                print(person.child?.name);
                //print undefined
                print(person.child?.name ?? 'not exist');
                //print not exist
            """.trimIndent()
            engine.eval(script)
        } catch (e: Exception) {
            throw e
        }
    }
}

【讨论】:

  • 注意你不需要设置.option("js.ecmascript-version", "2020"),无论如何这是当前的默认值(如果你想修复这个版本,你只需要设置它,而不是自动更新到新版本)未来。对于.option("js.nashorn-compat", "true"),你应该只在你真的需要时设置它。最好检查你的代码是否在没有 nashorn-compat 模式的情况下运行(从我在这里看到的,它应该!) - 兼容模式将你锁定在那个特定的环境;您可能需要更改一两件事,但这可以避免将来出现并发症。
  • 如果我移除 nashorn,如何将数据绑定到脚本?我想绑定Person 并在脚本中使用。@ChristianWirth
猜你喜欢
  • 2021-11-01
  • 2014-11-28
  • 1970-01-01
  • 2021-10-08
  • 2022-01-15
  • 2020-07-19
相关资源
最近更新 更多