我有一个JavaScript数组 dataArray
,我想推入一个新的数组 newArray
. 除了我不希望 newArray[0]
是 dataArray
. 我想将所有项目推入新数组:
var newArray = [];
newArray.pushValues(dataArray1);
newArray.pushValues(dataArray2);
// ...
甚至更好:
var newArray = new Array (
dataArray1.values(),
dataArray2.values(),
// ... where values() (or something equivalent) would push the individual values into the array, rather than the array itself
);
所以现在新数组包含各个数据数组的所有值 . 有没有像 pushValues
这样的简写,所以我不必遍历每个人 dataArray
,逐个添加项目?
15 回答
有很多答案在谈论Array.prototype.push.apply . 这是一个明显的例子:
如果你有ES6语法:
以下对我来说似乎最简单:
由于"push"采用可变数量的参数,因此可以使用
push
函数的apply
方法来推送另一个数组的所有元素 . 它构造一个使用其第一个参数(此处为"newArray")作为"this"进行推送的调用,并将该数组的元素作为其余参数 .第一个语句中的
slice
获取第一个数组的副本,因此不要修改它 .Update 如果您使用的是带有切片的javascript版本,则可以将
push
表达式简化为:而不是push()函数使用IE的concat函数 . 例,
最简单:
如果您的数组不是很大(请参阅下面的警告),您可以使用要附加值的数组的
push()
方法 .push()
可以使用多个参数,因此您可以使用其apply()
方法传递要作为函数参数列表推送的值数组 . 这比使用concat()
在数组中添加元素而不是创建新数组更有优势 .但是,似乎对于大型阵列(大约100,000个成员或更多), this trick can fail . 对于这样的数组,使用循环是一种更好的方法 . 有关详细信息,请参阅https://stackoverflow.com/a/17368101/96100 .
您可能希望将其概括为函数:
...或将其添加到
Array
的原型中:...或者使用
concat()
(如push()
)允许多个参数这一事实允许多个参数来模拟原始push()
方法:这是最后一个示例的基于循环的版本,适用于大型数组和所有主流浏览器,包括IE <= 8:
使用concat函数,如下所示:
newArray
的值将为[1, 2, 3, 4]
(arrayA
和arrayB
保持不变;concat
为结果创建并返回一个新数组) .Here's the ES6 way
使用JavaScript ES6,您可以使用...运算符作为扩展运算符,它实际上将数组转换为值 . 然后,你可以这样做:
虽然语法简洁,但我不知道它在内部如何工作以及对大型数组的性能影响 .
这会解决你的问题吗?
我将再添加一个“面向未来”的回复
在ECMAScript 6中,您可以使用spread operator:
Spread运算符尚未包含在所有主流浏览器中 . 有关当前兼容性,请参阅此(不断更新)compatibility table .
但是,您可以使用带有Babel.js的扩展运算符 .
编辑:
有关性能的更多评论,请参阅下面的Jack Giffin回复 . 似乎concat仍然比spread运算符更好更快 .
下面的函数没有数组长度的问题,并且性能优于所有建议的解决方案:
不幸的是,jspref拒绝接受我提交的内容,所以这里是使用benchmark.js的结果
哪里
for loop和push是:
推申请:
传播运营商:
最后'set length和for loop'是上面的函数
这是一个有效的代码,它工作正常:
研究和结果
对于事实,执行performance test at jsperf并检查控制台中的一些内容 . 对于研究,使用the website irt.org . 下面是所有这些来源的集合,以及底部的示例函数 .
如上所述,我认为Concat几乎总是能够保持性能和保留备用阵列稀疏性的能力 . 然后,对于类似数组(例如像
document.body.children
这样的DOMNodeLists),我建议使用for循环,因为它是第二个最高效的,也是唯一一个保留稀疏数组的方法 . 下面,我们将快速浏览稀疏数组和数组类似的意思,以消除混淆 .未来
起初,有些人可能认为这是一个侥幸,浏览器供应商最终会优化Array.prototype.push,以便足够快地击败Array.prototype.concat . 错误!Array.prototype.concat总是更快(原则上至少),因为它是对数据的简单复制粘贴 . 下面是一个简化的persuado-visual图,显示了32位阵列实现的样子(请注意实际实现很复杂)
如上所示,复制类似内容所需要做的就像将字节复制一样简单 . 使用Array.prototype.push.apply,它不仅仅是对数据的简单复制粘贴 . “.apply”必须检查数组中的每个索引,并在将其传递给Array.prototype.push之前将其转换为一组参数 . 然后,Array.prototype.push每次必须额外分配更多内存,并且(对于某些浏览器实现)甚至可能重新计算一些稀疏性的位置查找数据 .
想到它的另一种方法就是这样 . 源阵列之一是钉在一起的大量纸张 . 源数组二也是另一大堆文件 . 你会更快吗?
去商店,购买每个源阵列副本所需的足够纸张 . 然后将每个源阵列纸叠通过复印机并将所得到的两个副本装订在一起 .
去商店,为第一个源阵列的单个副本购买足够的纸张 . 然后,手动将源数组复制到新纸上,确保填充任何空白的稀疏点 . 然后,回到商店,为第二个源阵列购买足够的纸张 . 然后,浏览第二个源阵列并复制它,同时确保副本中没有空白间隙 . 然后,将所有复印的纸张装订在一起 .
在上面的类比中,选项#1表示Array.prototype.concat,而#2表示Array.prototype.push.apply . 让我们用类似的JSperf来测试它,不同之处在于这个方法测试稀疏数组上的方法,而不是实数数组 . 人们可以找到它right here .
因此,我认为这个特定用例的性能未来不在于Array.prototype.push,而在于Array.prototype.concat .
澄清
备用阵列
当阵列的某些成员丢失时 . 例如:
或者,javascript允许您轻松初始化备用阵列 .
Array-Likes
类数组是一个至少具有
length
属性但未使用new Array
或[]
初始化的对象;例如,以下对象被分类为类似数组 .观察使用一种将阵列类似强制转换为像slice这样的数组的方法会发生什么 .
观察使用 not 将数组喜欢强制转换为像concat这样的数组的方法会发生什么 .
我们有两个数组a和b . 这里的代码是数组,一个值被推入数组b .
找到一个优雅的方式MDN
或者您可以使用ES6的
spread operator
功能: