本文重点介绍 Nashorn – 从 Java 8 开始,JVM 的新默认 JavaScript 引擎。
许多复杂的技术已被用于使 Nashorn 的性能比其前身 Rhino 高出几个数量级,因此这是一个值得的改变。让我们来看看它的一些使用方式。
本文大部分内容翻译自:https://www.baeldung.com/java-nashorn
JDK 1.8 包含一个名为 jjs 的命令行解释器,它可用于运行 JavaScript 文件,或者,如果没有参数,则用作 REPL(交互式 shell):
$JAVA_HOME/bin/jjs hello.js
Hello World
这里的文件 hello.js 包含一条指令:
print("Hello world");
相同的代码可以以交互方式运行:
$JAVA_HOME/bin/jjs
jjs> print("Hello world")
Hello world
您还可以通过添加 #!$JAVA_HOME/bin/jjs
作为第一行来指示 *nix 运行时使用 jjs 来运行目标脚本:
#!$JAVA_HOME/bin/jjs
var greeting = "Hello World";
print(greeting);
然后文件可以正常运行:
$ ./hello.js
Hello World
PS: 我在macOS之中把上面的第1行替换成
#!/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/bin/jjs
暂不清楚为什么$JAVA_HOME
没有正确认识出来,我猜测我的$JAVA_HOME
变量是用户级别的,而直接运行.js可能无法访问到我的用户的变量。
在 JVM 中运行 JavaScript 的第二种可能更常见的方法是通过 ScriptEngine。JSR-223 定义了一组脚本 API,允许一个可插拔的脚本引擎架构,该架构可用于任何动态语言(当然,前提是它有一个 JVM 实现)。
让我们创建一个 JavaScript 引擎:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
Object result = engine.eval(
"var greeting='hello world';" +
"print(greeting);" +
"greeting");
在这里,我们创建一个新的 ScriptEngineManager,并立即要求它为我们提供一个名为 nashorn 的 ScriptEngine。然后,我们传递几个指令并获得结果,可以预见的是,结果是一个字符串“hello world”。
可以通过定义 Bindings 对象并将其作为第二个参数传递给 eval 函数来将数据传递到引擎中:
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class 将数据传递给脚本 {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
Bindings bindings = engine.createBindings();
bindings.put("count", 3);
bindings.put("name", "baeldung");
String script = "var greeting='Hello ';" +
"for(var i=count;i>0;i--) { " +
"greeting+=name + ' '" +
"}" +
"greeting";
Object bindingsResult = engine.eval(script, bindings);
System.out.println(bindingsResult);
}
}
运行此代码段会产生:“Hello baeldung baeldung baeldung”。
当然,可以从 Java 代码中调用 JavaScript 函数:
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class 调用Javascript函数 {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval("function composeGreeting(name) {" +
"return 'Hello ' + name" +
"}");
Invocable invocable = (Invocable) engine;
Object funcResult = invocable.invokeFunction("composeGreeting", "baeldung");
System.out.println(funcResult);
}
}
这将返回“Hello baeldung”。
由于我们在 JVM 中运行,因此可以在 JavaScript 代码中使用本机 Java 对象。
这是通过使用 Java 对象实现的:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class 使用Java对象 {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
Object map = engine.eval("var HashMap = Java.type('java.util.HashMap');" +
"var map = new HashMap();" +
"map.put('hello', 'world');" +
"map");
System.out.println(map);
}
}
Nashorn 的目标是 ECMAScript 5.1,但它确实提供了扩展,使 JavaScript 的使用变得更好一些。
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleScriptContext;
public class NashornTest {
public static void main(String[] args) throws Exception {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("nashorn");
final String raw = "I am the raw value injected";
final ScriptContext ctx = new SimpleScriptContext();
// **This is the inserted line**
ctx.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE);
String script = "var result = 'I am a result';";
script += "java.lang.System.out.println(raw);";
script += "'I am a returned value';";
final Object res = engine.eval(script, ctx);
System.out.println(ctx.getAttribute("result"));
System.out.println(res);
}
}
摘自:
https://stackoverflow.com/questions/42338239/access-variable-of-scriptcontext-using-nashorn-javascript-engine-java-8
https://www.baeldung.com/java-nashorn