如何在Rhino中创建一个“真正的”JavaScript数组

7

好的,我有点困惑。我可能漏掉了一些非常明显的东西,但显然我只能看到树木而看不到森林:

我试图调用一个期望其参数为数组的JavaScript函数,即它会检查 if (arg instanceof Array)... 不幸的是,我(或Rhino)似乎无法创建这样的数组:

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

哎呀,结果是 false

我错过了什么吗?

编辑:
再多提供一点信息: [] instanceof Arraynew Array() instanceof Array 都像人们期望的那样返回 true。如果我向数组中添加元素,它们会在 JavaScript 代码中以正确的索引(数字,从零开始)显示:

  NativeArray a = new NativeArray(new Object[]{ 42, "foo" });

使用此JavaScript函数输出时:
  function f(a) {
      var result = [];
      result.push(typeof a);
      for (var i in a) {
          result.push(i + ' => ' + a[i]);
      }
      return result.join('\\n');
  }

结果是:
  object
  0 => 42
  1 => foo

它能工作。除了我想要一个“真正”的数组 :)


1
你能否在f()中添加一些诊断功能,以查明实际接收到的参数是什么? - djna
我添加了一些信息,也许那会有所帮助。 - n3rd
1
这个库正在进行的检查(a instanceof Array)是合理的,但有限。例如,即使没有Rhino,在基于浏览器的应用程序中,如果数组源自另一个窗口,它也无法识别数组。您会尝试将result.push(Object.prototype.toString.call(a));添加到函数中吗?看看它是否会显示“[object Object]”或“[object Array]”,这将类似于来自另一个窗口的数组,前者表明“NativeArray”并不像其名称所示。 - T.J. Crowder
你有 NativeArray 的 JavaDoc 吗?因为这里似乎没有:http://www.mozilla.org/rhino/apidocs/ - T.J. Crowder
在这种情况下,我不担心任何限制,因为我只是试图在我们的构建过程中运行JSLint(即我完全控制将什么作为参数传递给JSLint)。new NativeArray()与调用Context.newArray()相同。http://mxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/javascript/NativeArray.java - n3rd
几乎忘记了:Object.prototype.toString.call(a) 返回 [object Array] - n3rd
2个回答

8

几乎忘记了:Object.prototype.toString.call(a) 返回 [object Array]

好的,这是至关重要的信息。它告诉我们这个数组确实是一个数组,只是它是由不同作用域中的Array构造函数初始化的,就像在基于浏览器的应用程序中从一个窗口测试另一个窗口的Array构造函数一样。例如,存在作用域问题。

尝试替换

Object[] fArgs = new Object[]{ new NativeArray(0) };

使用

Object[] fArgs = new Object[]{ cx.newArray(scope, 0) };

为了确保使用正确的Array构造函数,您需要注意。因为您直接使用了NativeArray构造函数,所以绕过了确保其范围正确的步骤,因此数组对象的constructor是一个Array构造函数,但不是函数看到的全局对象上的相同Array构造函数。


我刚刚自己找到了答案,尽管我发誓今天早些时候我尝试过那个方法。谢谢! - n3rd

1
对于那些有意创建不同子类的数组实现,因此无法使用cx.newArray的人,您可以这样做: 添加以下行 ScriptRuntime.setBuiltinProtoAndParent(fArgs, scope, TopLevel.Builtins.Array);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接