本文翻译自:How to extend an existing JavaScript array with another array, without creating a new array
There doesn't seem to be a way to extend an existing JavaScript array with another array, ie to emulate Python's extend
method. 似乎没有办法用另一个数组扩展现有的JavaScript数组,即模拟Python的extend
方法。
I want to achieve the following: 我想实现以下目标:
>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]
I know there's a a.concat(b)
method, but it creates a new array instead of simply extending the first one. 我知道有一个a.concat(b)
方法,但它创建了一个新数组,而不是简单地扩展第一个数组。 I'd like an algorithm that works efficiently when a
is significantly larger than b
(ie one that does not copy a
). 我想要一个算法,当a
明显大于b
(即不复制a
的算法),它可以有效地工作。
Note: This is not a duplicate of How to append something to an array? 注意:这不是如何将某些内容附加到数组的副本? -- the goal here is to add the whole contents of one array to the other, and to do it "in place", ie without copying all elements of the extended array. - 这里的目标是将一个数组的全部内容添加到另一个数组中,并“就地”执行,即不复制扩展数组的所有元素。
#1楼
参考:https://stackoom.com/question/5lTK/如何使用另一个数组扩展现有JavaScript数组-而无需创建新数组
#2楼
The .push
method can take multiple arguments. .push
方法可以使用多个参数。 You can use the spread operator to pass all the elements of the second array as arguments to .push
: 您可以使用spread运算符将第二个数组的所有元素作为参数传递给.push
:
>>> a.push(...b)
If your browser does not support ECMAScript 6, you can use .apply
instead: 如果您的浏览器不支持ECMAScript 6,则可以使用.apply
:
>>> a.push.apply(a, b)
Or perhaps, if you think it's clearer: 或许,如果你认为它更清楚:
>>> Array.prototype.push.apply(a,b)
Please note that all these solutions will fail with a stack overflow error if array b
is too long (trouble starts at about 100,000 elements, depending on the browser). 请注意,如果阵列b
太长,所有这些解决方案都会因堆栈溢出错误而失败(麻烦从大约100,000个元素开始,具体取决于浏览器)。 If you cannot guarantee that b
is short enough, you should use a standard loop-based technique described in the other answer. 如果你不能保证b
足够短,你应该使用另一个答案中描述的基于循环的标准技术。
#3楼
I like the a.push.apply(a, b)
method described above, and if you want you can always create a library function like this: 我喜欢上面描述的a.push.apply(a, b)
方法,如果你想要,你总是可以像这样创建一个库函数:
Array.prototype.append = function(array)
{
this.push.apply(this, array)
}
and use it like this 并像这样使用它
a = [1,2]
b = [3,4]
a.append(b)
#4楼
It is possible to do it using splice()
: 可以使用splice()
来完成它:
b.unshift(b.length)
b.unshift(a.length)
Array.prototype.splice.apply(a,b)
b.shift() // Restore b
b.shift() //
But despite being uglier it is not faster than push.apply
, at least not in Firefox 3.0. 但是尽管比较丑陋,它并不比push.apply
快,至少在Firefox 3.0中没有。
#5楼
You should use a loop-based technique. 您应该使用基于循环的技术。 Other answers on this page that are based on using .apply
can fail for large arrays. 此页面上基于使用.apply
其他答案可能会因大型阵列而失败。
A fairly terse loop-based implementation is: 一个相当简洁的基于循环的实现是:
Array.prototype.extend = function (other_array) {
/* You should include a test to check whether other_array really is an array */
other_array.forEach(function(v) {this.push(v)}, this);
}
You can then do the following: 然后,您可以执行以下操作:
var a = [1,2,3];
var b = [5,4,3];
a.extend(b);
DzinX's answer (using push.apply) and other .apply
based methods fail when the array that we are appending is large (tests show that for me large is > 150,000 entries approx in Chrome, and > 500,000 entries in Firefox). 当我们追加的阵列很大时, DzinX的答案 (使用push.apply)和其他基于.apply
的方法都会失败(测试显示,对我来说,Chrome中大约150,000个条目,Firefox中大于500,000个条目)。 You can see this error occurring in this jsperf . 您可以在此jsperf中看到此错误。
An error occurs because the call stack size is exceeded when 'Function.prototype.apply' is called with a large array as the second argument. 发生错误是因为当使用大数组作为第二个参数调用'Function.prototype.apply'时,超出了调用堆栈大小。 (MDN has a note on the dangers of exceeding call stack size using Function.prototype.apply - see the section titled "apply and built-in functions".) (MDN记录了使用Function.prototype.apply超出调用堆栈大小的危险 - 请参阅标题为“应用和内置函数”的部分。)
For a speed comparison with other answers on this page, check out this jsperf (thanks to EaterOfCode). 要与本页面上的其他答案进行速度比较,请查看此jsperf (感谢EaterOfCode)。 The loop-based implementation is similar in speed to using Array.push.apply
, but tends to be a little slower than Array.slice.apply
. 基于循环的实现与使用Array.push.apply
速度类似,但往往比Array.slice.apply
慢一点。
Interestingly, if the array you are appending is sparse, the forEach
based method above can take advantage of the sparsity and outperform the .apply
based methods; 有趣的是,如果你追加的数组是稀疏的,那么上面基于forEach
的方法可以利用稀疏性并优于基于.apply
的方法; check out this jsperf if you want to test this for yourself. 如果你想亲自测试一下,请查看这个jsperf 。
By the way, do not be tempted (as I was!) to further shorten the forEach implementation to: 顺便说一句,不要被诱惑(像我一样!)进一步缩短forEach实现:
Array.prototype.extend = function (array) {
array.forEach(this.push, this);
}
because this produces garbage results! 因为这会产生垃圾结果! Why? 为什么? Because Array.prototype.forEach
provides three arguments to the function it calls - these are: (element_value, element_index, source_array). 因为Array.prototype.forEach
为它调用的函数提供了三个参数 - 这些参数是:(element_value,element_index,source_array)。 All of these will be pushed onto your first array for every iteration of forEach
if you use "forEach(this.push, this)"! 如果你使用“forEach(this.push,this)”,那么所有这些都会被推送到你的第一个数组,用于forEach
每次迭代!
#6楼
Combining the answers... 结合答案......
Array.prototype.extend = function(array) {
if (array.length < 150000) {
this.push.apply(this, array)
} else {
for (var i = 0, len = array.length; i < len; ++i) {
this.push(array[i]);
};
}
}