我正在尝试将一些库预加载到全局范围内(诸如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');");
是否有一种解决方法可以使它按预期工作,即,更改已从全局范围正确传播到引擎范围?
全局作用域只能用于简单的变量映射。例如:
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
所以您有三个选择:
--global-per-engine option
使用-Dnashorn.args=--global-per-engine
。然后,Nashorn将对所有脚本评估使用全局对象的单个实例,而不管传递的ScriptContext如何。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);