如何在Nashorn中不使用internal子包类让Java数组被识别为JS数组
解决Nashorn中Java数组被识别为JS数组的问题
遇到这种情况太常见了——直接把Java数组传给Nashorn,结果JS里Array.isArray()不认它,确实头疼。不用碰那些internal包的私有类,有两种标准API的方案可以解决,而且完全符合要求,不用修改JS源码。
方案一:通过JS代码转换(最直观)
核心思路是利用JS原生的数组方法,把类数组的Java数组转换成真正的JS数组。具体步骤:
- 先把Java数组放到ScriptEngine的上下文里
- 执行一段JS代码,用
Array.prototype.slice.call()或者Array.from()(Java 8u40+的Nashorn支持部分ES6特性)把Java数组转成JS数组,再存回目标变量
示例代码:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); Object[] javaArray = {1, 2, 3}; // 先把Java数组传入上下文 engine.put("javaArray", javaArray); // 执行转换,生成真正的JS数组并赋值给prop engine.eval("var prop = Array.prototype.slice.call(javaArray);"); // 验证结果 boolean isArray = (boolean) engine.eval("Array.isArray(prop)"); System.out.println(isArray); // 输出true
Array.prototype.slice.call()能把任何类数组对象(有length属性、可按索引访问)转成真正的JS数组,完美适配Nashorn包装后的Java数组。
方案二:通过Java的Invocable接口调用JS方法(更Java风格)
如果你不想在代码里写JS字符串,可以用Invocable接口直接调用JS的Array.apply()方法来创建数组:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); Object[] javaArray = {1, 2, 3}; Invocable invocable = (Invocable) engine; // 获取JS的Array构造函数 Object arrayConstructor = engine.eval("Array"); // 用apply方法把Java数组转成JS数组:Array.apply(null, javaArray) Object jsArray = invocable.invokeMethod(arrayConstructor, "apply", null, javaArray); // 把转换后的JS数组存入上下文 engine.put("prop", jsArray); // 验证 boolean isArray = (boolean) engine.eval("Array.isArray(prop)"); System.out.println(isArray); // 输出true
这个方法完全用Java代码完成转换,不需要嵌入JS片段,适合对代码风格有统一要求的场景。
为什么直接传Java数组不行?
Nashorn会把Java数组包装成一个类数组对象——它有length属性,也能通过索引访问元素,但本质上不是JS原生Array的实例,所以Array.isArray()会返回false。上面的两种方法都是把这个类数组对象转换成真正的JS数组实例,自然就能通过Array.isArray()的检测了。
内容的提问来源于stack exchange,提问作者Alexey Subach
相关产品推荐
相关产品推荐

