【问题标题】:Why can't I convert the "argument" object to an array with concat method in JavaScript?为什么我不能在 JavaScript 中使用 concat 方法将“参数”对象转换为数组?
【发布时间】:2015-06-09 09:21:41
【问题描述】:

我正在尝试将 arguments 对象与另一个数组连接,我编写了如下代码:

[].concat.call(arguments, newArray)

但它返回[ [object Arguments], ... ],这完全不是我想要的。我用谷歌搜索并找到了一些解释为什么我可以通过 slice 方法做到这一点:How can I convert the "arguments" object to an array in JavaScript?

但是在查阅了规范之后,我在 concat 方法上发现了相同的定义:

注意 concat 函数是故意通用的;它不要求它的 this 值是一个 Array 对象。因此,它可以转移到其他类型的对象中用作方法。 concat 函数能否成功应用于宿主对象取决于实现。

规格在这里:http://es5.github.io/#x15.4.4.4

所以现在我很困惑为什么我不能通过concat 方法将arguments 对象转换为数组。

【问题讨论】:

  • “我写了这样的代码” newArray是什么?
  • 查看步骤 5b 和 5c。这就是为什么。注释似乎与算法有所不同。但注释显然是非正式的。
  • 这是另一个数组,例如 [ 1, 2, 3 ]
  • 这在 ES6 中有所改变(至少在理论上):: people.mozilla.org/~jorendorff/…
  • @T.J.Crowder:这就是我添加“理论上”的原因。至少它不再将其限制为数组,除非数组是唯一实现该属性的东西:-/很可能是,现在我正在考虑它,因为改变它会破坏向后兼容性?跨度>

标签: javascript arrays arguments


【解决方案1】:

详情请见§15.4.4.4 of the spec。基本上,它首先创建一个要处理的事物列表,其中列表中的第一项是您调用它的对象 (this),然后列表中的后续项是函数的参数。然后它遍历列表并处理每个项目。对于该列表中不是数组的项目,它在其中有一个明确的分支,并且该分支的“其他”是(步骤 5(c)):

  • 否则,E 不是数组
    • 使用参数 ToString(n) 调用 A 的 [[DefineOwnProperty]] 内部方法,属性描述符 {[[Value]]: E, [[Writable]]: true, [[Enumerable]]: true, [[可配置]]:true} 和 false。
    • 将 n 增加 1。

所以你可以在非数组上调用concat。它不会失败。但它不会将非数组类数组的东西视为数组。

注意Felix's observation,这种“只有数组才能分散它们的条目”在 ES6 中发生了变化。 concat 在对象上使用新的"is concat spreadable" flag 来确定它是否应该遍历它们的条目。不过,我认为arguments 对象不会有该标志(至少,我在§9.4.4 中没有看到任何说法),可能是为了避免向后兼容性问题。

【讨论】:

  • 感谢您的解释。看来我提出了一个愚蠢的问题:P
  • @DolphinWood:我不会这么说。阅读规范并不像想象的那么容易(遗憾的是,情况变得更糟,而不是更好——ES6 规范让 ES5 规范看起来像一本儿童读物!)。
猜你喜欢
  • 2019-04-14
  • 1970-01-01
  • 2021-04-25
  • 2012-12-28
  • 2021-09-23
  • 2017-06-09
  • 1970-01-01
  • 1970-01-01
  • 2021-01-09
相关资源
最近更新 更多