How to create a 'real' JavaScript array in Rhino
Asked Answered
A

2

7

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 that I want a 'real' array :)

Asterism answered 22/6, 2010 at 6:57 Comment(6)
Could you add some diagnistics to f() to find out what the argument you get actually is?Koressa
I added some information, maybe that helpsAsterism
The check that the library is doing (a instanceof Array) is reasonable, but limited. For instance, even without Rhino, it would fail to identify an array in a browser-based application if that array originated in another window. Would you try adding result.push(Object.prototype.toString.call(a)); to your function? It'll be interesting to see whether it says [object Object] or [object Array]. The latter would be similar to an array from another window, the former would indicate that NativeArray wasn't quite what the name implies.May
Do you have JavaDoc for NativeArray? Because there doesn't seem to be any here: mozilla.org/rhino/apidocsMay
In this particular case I'm not worried about any such limitations as I'm simply trying to run JSLint during our build process (i.e. I've complete control over what is being passed as the parameters to JSLint) new NativeArray() is the same as calling Context.newArray() mxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/…Asterism
Almost forgot: Object.prototype.toString.call(a) returns [object Array]Asterism
M
8

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.

May answered 22/6, 2010 at 9:24 Comment(1)
I just figured that out myself, although I could've sworn I tried that earlier today. Thanks!Asterism
L
1

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);

Lindstrom answered 21/2, 2013 at 14:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.