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

发布于 2024-09-06 12:53:30 字数 1319 浏览 6 评论 0原文

好吧,我有点难住了。我可能遗漏了一些明显的东西,但显然我只是只见树木不见森林:

我正在尝试调用一个 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();

唉,resultfalse

我在这里缺少什么?

编辑
更多信息:[] 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

所以它有效。除了我想要一个“真正的”数组:)

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

裸钻 2024-09-13 12:53:30

差点忘了: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 构造函数,所以您绕过了确保其范围正确的步骤,因此数组对象的 构造函数一个 Array 构造函数,但与函数所看到的全局对象上的相同 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.

寄人书 2024-09-13 12:53:30

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文