How to create a 'real' JavaScript array in Rhino
Okay, I'm a little stumped. I'm probably missing something blatantly obvious but apparently I just can't see the forest for the trees:
I'm trying to call a JavaScript function that expects its parameter to be an array, i.e. it checks if (arg instanceof Array)...
Unfortunately, I (or Rhino) just can't seem to create such an array:
Context cx = Context.enter();
Scriptable scope = cx.initStandardObjects();
String src = "function f(a) { return a instanceof Array; };";
cx.evaluateString(scope, src, "<src>", 0, null);
Function f = (Function) scope.get("f", scope);
Object[] fArgs = new Object[]{ new NativeArray(0) };
Object result = f.call(cx, scope, scope, fArgs);
System.out.println(Context.toString(result));
Context.exit();
And alas, result
is false
.
What am I missing here?
Edit:
Just a little more information: both[] instanceof Array
and new Array() instanceof Array
return true
as one would expect. If I add elements to the array they show up in the JavaScript code with the right indices (numeric, starting from zero):
NativeArray a = new NativeArray(new Object[]{ 42, "foo" });
When output using this JavaScript function:
function f(a) {
var result = [];
result.push(typeof a);
for (var i in a) {
result.push(i + ' => ' + a[i]);
}
return result.join('\\n');
}
The result is:
object
0 => 42
1 => foo
So it works. Except t开发者_开发问答hat I want a 'real' array :)
Almost forgot:
Object.prototype.toString.call(a)
returns[object Array]
Okay, that's the crucial information. That tells us that the array really is an array, it's just that it's being initialized by an Array
constructor in a different scope than the one that the function is testing for, exactly as though you were testing an array from one window against another window's Array
constructor in a browser-based app. E.g., there's a scope problem.
Try replacing
Object[] fArgs = new Object[]{ new NativeArray(0) };
with
Object[] fArgs = new Object[]{ cx.newArray(scope, 0) };
...to ensure the correct Array
constructor is used. Because you've gone directly to the NativeArray
constructor, you've bypassed ensuring that its scope is right, and so the array object's constructor
is an Array
constructor, but not the same Array
constructor as the one on the global object the function sees.
For those who are intentionally creating a different subclass of the array implementation, and therefore can't use cx.newArray, what you can do is:
add this line
ScriptRuntime.setBuiltinProtoAndParent(fArgs, scope, TopLevel.Builtins.Array);
精彩评论