似乎没有办法用另一个数组来扩展一个现有的JavaScript数组,即模仿Python的extend方法。
我想达到以下几点:
>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]
我知道有一个a.c concat(b)方法,但它创建了一个新数组,而不是简单地扩展第一个数组。我想要一个算法,有效地工作时,a明显大于b(即一个不复制a)。
注意:这不是“如何将内容追加到数组?”这里的目标是将一个数组的全部内容添加到另一个数组中,并做到“就地”,即不复制扩展数组的所有元素。
答案非常简单。
>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
(The following code will combine the two arrays.)
a = a.concat(b);
>>> a
[1, 2, 3, 4, 5]
Concat的作用与JavaScript字符串连接非常相似。它将返回您在调用函数的数组末尾放入concat函数的参数的组合。关键是你必须把返回值赋给一个变量,否则它就会丢失。例如,
a.concat(b); <--- This does absolutely nothing since it is just returning the combined arrays, but it doesn't do anything with it.
我添加了这个答案,因为尽管这个问题没有创建一个新数组,但几乎每个答案都忽略了它。
现代JavaScript可以很好地处理数组等可迭代对象。这使得在此基础上实现一个版本的concat成为可能,并在逻辑上跨越数组数据的参数。
下面的例子使用了iter-ops库,它具有这样的逻辑:
import {pipe, concat} from 'iter-ops';
const i = pipe(
originalArray,
concat(array2, array3, array4, ...)
); //=> Iterable
for(const a of i) {
console.log(a); // iterate over values from all arrays
}
上面没有创建新数组。操作符concat将遍历原始数组,然后按照指定的顺序自动继续到array2、array3等等。
就内存使用而言,这是最有效的连接数组的方法。
如果在最后,你决定将它转换为一个实际的物理数组,你可以通过展开操作符或array .from来实现:
const fullArray1 = [...i]; // pulls all values from iterable, into a new array
const fullArray2 = Array.from(i); // does the same
您应该使用基于循环的技术。本页上基于.apply的其他答案对于大型数组可能会失败。
一个相当简洁的基于循环的实现是:
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);
}
然后您可以执行以下操作:
var a = [1,2,3];
var b = [5,4,3];
a.extend(b);
DzinX的答案(使用push.apply)和其他基于.apply的方法失败时,我们附加的数组很大(测试表明,对我来说,大是>大约150000个条目在Chrome, > 500000个条目在Firefox)。您可以在这个jsperf中看到这个错误。
当'Function.prototype. size '时,调用堆栈大小超过,因此发生错误。Apply '调用时使用一个大数组作为第二个参数。(MDN有一个关于使用Function.prototype.apply超过调用堆栈大小的危险的说明-请参阅标题为“apply和内置函数”的部分。)
要与本页上的其他答案进行速度比较,请查看这个jsperf(感谢EaterOfCode)。基于循环的实现在速度上与使用Array.push类似。apply,但往往比Array.slice.apply慢一点。
有趣的是,如果你要追加的数组是稀疏的,上面基于forEach的方法可以利用稀疏性并优于基于.apply的方法;如果您想亲自测试,请查看这个jsperf。
顺便说一下,不要试图(像我一样!)进一步缩短forEach实现为:
Array.prototype.extend = function (array) {
array.forEach(this.push, this);
}
因为这会产生垃圾结果!为什么?因为Array.prototype.forEach为它调用的函数提供了三个参数(element_value, element_index, source_array)。如果你使用“forEach(this。推动,这)”!