java - 原型(prototype)在 nashorn 中从 globalscope 更改为 enginescope

标签 java nashorn scriptengine

我正在尝试将一些库预加载到全局范围内(例如 chai.js)。这改变了一些对象的原型(prototype),我意识到这适用于 ENGINE_SCOPE 但不适用于 GLOBAL_SCOPE。

最小的例子:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
Bindings globalBindings = engine.createBindings();
engine.eval("Object.prototype.test = function(arg){print(arg);}", globalBindings);

//works as expected, printing "hello"
engine.getContext().setBindings(globalBindings, ScriptContext.ENGINE_SCOPE);
engine.eval("var x = {}; x.test('hello');");

//throws TypeError: null is not a function in <eval> at line number 1
engine.getContext().setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
engine.getContext().setBindings(globalBindings, ScriptContext.GLOBAL_SCOPE);
engine.eval("var x = {}; x.test('hello');");

是否有解决方法使其按预期工作,即更改从全局范围正确传播到引擎范围?

最佳答案

为什么你的代码不起作用

全局作用域只能用于简单的变量映射。例如:

ScriptContext defCtx = engine.getContext();
defCtx.getBindings(ScriptContext.GLOBAL_SCOPE).put("foo", "hello");

Object 存在于引擎范围内,因此甚至不会在全局范围内搜索与其相关的任何映射(在您的情况下为 Object.prototype.test)。

文档摘录:

The default context's ENGINE_SCOPE is a wrapped instance of ECMAScript "global" object - which is the "this" in top level script expressions. So, you can access ECMAScript top-level objects like "Object", "Math", "RegExp", "undefined" from this scope object. Nashorn Global scope object is represented by an internal implementation class called jdk.nashorn.internal.objects.Global. Instance of this class is wrapped as a jdk.nashorn.api.scripting.ScriptObjectMirror instance. ScriptObjectMirror class implements javax.script.Bindings interface. Please note that the context's GLOBAL_SCOPE Bindings and nashorn global object are different. Nashorn's global object is associated with ENGINE_SCOPE and not with GLOBAL_SCOPE. GLOBAL_SCOPE object of default script context is a javax.script.SimpleBindings instance.The user can fill it with name, value pairs from the java code.

https://wiki.openjdk.java.net/display/Nashorn/Nashorn+jsr223+engine+notes

解决方案

  1. 继续使用引擎作用域
  2. 通过在 Java 命令行中指定 -Dnashorn.args=--global-per-engine 来使用 --global-per-engine 选项。然后 Nashorn 将使用全局对象的单个实例进行所有脚本评估,无论是否传递了 ScriptContext。
  3. 使用成熟的 ScriptContext 而不是 Bindings:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
SimpleScriptContext context = new SimpleScriptContext();
engine.eval("Object.prototype.test = function(arg){print(arg);}", context);
engine.eval("var x = {}; x.test('hello');", context);

如何运行多个脚本,每次都加载库,但之前的执行没有留下任何东西

每次您需要一个带有库的新上下文时,只需创建它:

public static void main(String[] args) throws ScriptException {
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    SimpleScriptContext context1 = createContextWithLibraries(engine);
    //works as expected, printing "hello"
    engine.eval("var x = {}; x.test('hello'); var y = 'world';", context1);
    SimpleScriptContext context2 = createContextWithLibraries(engine);
    //works as expected, printing "hello"
    engine.eval("var x = {}; x.test('hello');", context2);
    //works as expected, printing "world"
    engine.eval("print(y);", context1);
    //fails with exception since there is no "y" variable in context2
    engine.eval("print(y);", context2);
}

private static SimpleScriptContext createContextWithLibraries(ScriptEngine engine) throws ScriptException {
    SimpleScriptContext context = new SimpleScriptContext();
    engine.eval("Object.prototype.test = function(arg){print(arg);}", context);
    return context;
}

关于java - 原型(prototype)在 nashorn 中从 globalscope 更改为 enginescope,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60946483/

相关文章:

javax.script.ScriptEngine 控制台扩展或库?

java - 一些 Collection

java - android 在 Java 中使用 for 循环遍历按钮 id

java - Nashorn 和 Rhino : Splitting strings by whitespace regexp

java - 在从 Maven 运行的测试中使用 Kotlin `ScriptException` 时获取 `ScriptEngine`

java - 由于 XOR 按位 ^ 运算符,Java 中的 JavaScript 表达式的返回值类型不正确

java - 当角度接近 90 时,子弹会变得 super 快

java - 如何检查直线和矩形之间的交点?

java - Cassandra:无法为 javascript 创建 javax 脚本引擎

java - 向 nashorn 中的 java pojo 添加新属性