原型在nashorn中从globalscope更改为enginescope

问题描述 投票:1回答:1

我正在尝试将一些库预加载到全局范围内(诸如chai.js之类的东西)。这改变了某些对象的原型,我意识到这适用于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');");

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

java nashorn scriptengine
1个回答
1
投票

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

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

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

摘录自文档:

默认上下文的ENGINE_SCOPE是ECMAScript“全局”对象的包装实例-顶级脚本表达式中的“ this”。因此,您可以从此范围对象访问ECMAScript顶级对象,例如“对象”,“数学”,“ RegExp”,“未定义”。 Nashorn全局范围对象由称为jdk.nashorn.internal.objects.Global的内部实现类表示。此类的实例包装为jdk.nashorn.api.scripting.ScriptObjectMirror实例。 ScriptObjectMirror类实现javax.script.Bindings接口。请注意,上下文的GLOBAL_SCOPE绑定和nashorn全局对象是不同的。 Nashorn的全局对象与ENGINE_SCOPE关联,而不与GLOBAL_SCOPE关联。默认脚本上下文的GLOBAL_SCOPE对象是一个javax.script.SimpleBindings实例。用户可以使用Java代码中的名称和值对来填充它。

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

所以您有三个选择:

  1. 保持使用引擎范围
  2. 通过在Java命令行中指定--global-per-engine option使用-Dnashorn.args=--global-per-engine。然后,Nashorn将对所有脚本评估使用全局对象的单个实例,而不管传递的ScriptContext如何。
  3. 使用成熟的ScriptContext而不是绑定:
  4. 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);
    
© www.soinside.com 2019 - 2024. All rights reserved.