如何使用另一个数组扩展现有JavaScript数组,而无需创建新数组

本文翻译自: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]);
        };
    }  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值