Nashorn 里经典的 “原型污染可见性” 问题:
- 扩展了
Array.prototype.add = ... - Nashorn 把 原型上的可枚举属性 也当成 数组元素 返回给 Java
- 于是 Java 侧拿到
Object[]时,最后一个元素就是字符串"add"
快速复现
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(
"Array.prototype.add = function (v) {" +
" if (this.indexOf(v) == -1) this.push(v);" +
"};" +
"var a = [1, 2, 3];" +
"a.add(4);" +
"a;"
);
Object[] arr = (Object[]) engine.get("a");
System.out.println(Arrays.toString(arr));
输出:
[1, 2, 3, 4, add]
原因剖析
- Nashorn 的
NativeArray在 for-in 枚举 时会 把原型链上可枚举属性一起列出(符合 ECMA-262 规范,但和浏览器默认行为不同)。 - 当你把数组返回给 Java,内部走
JSObject::getOwnProperty(true)→ 包含原型可枚举属性 → 被 Java 反射成元素。
解决方案(任选其一)
✅ 方案 1:定义成 不可枚举 属性(推荐)
Object.defineProperty(Array.prototype, 'add', {
value: function (v) { if (this.indexOf(v) === -1) this.push(v); },
enumerable: false, // 关键
writable: true,
configurable: true
});
再执行,"add" 不再出现在 Object[] 里。
✅ 方案 2:返回前手动过滤(不改动原型)
var a = [1, 2, 3];
a.add(4);
// 只保留数字元素
var pure = a.filter(function (it) { return typeof it === 'number'; });
pure; // 返回这个给 Java
✅ 方案 3:Java 侧过滤
Object[] arr = (Object[]) engine.eval("a;");
List<Object> list = Arrays.stream(arr)
.filter(o -> o instanceof Number)
.collect(Collectors.toList());
最后
给原型加方法时,务必
enumerable: false,
否则 Nashorn 会把方法名当成数组元素暴露给 Java。
1147

被折叠的 条评论
为什么被折叠?



