Javascript 处理数组时使用扩展语法(…)和push.apply的区别
我有两个数组Javascript 处理数组时使用扩展语法(…)和push.apply的区别,javascript,arrays,ecmascript-6,apply,spread-syntax,Javascript,Arrays,Ecmascript 6,Apply,Spread Syntax,我有两个数组 const pets = ["dog", "cat", "hamster"] const wishlist = ["bird", "snake"] 我想将wishlist附加到pets,这可以使用两种方法完成 方法1: pets.push.apply(pets,wishlist) 结果是:[‘狗’、‘猫’、‘仓鼠’、‘鸟’、‘蛇’] 方法2: pets.push(...wishlist) 这也导致:[‘狗’、‘猫’、‘仓鼠’、‘鸟’、‘蛇’] 在处理较大数据时,这两种方法在
const pets = ["dog", "cat", "hamster"]
const wishlist = ["bird", "snake"]
我想将wishlist
附加到pets
,这可以使用两种方法完成
方法1:
pets.push.apply(pets,wishlist)
结果是:[‘狗’、‘猫’、‘仓鼠’、‘鸟’、‘蛇’]
方法2:
pets.push(...wishlist)
这也导致:[‘狗’、‘猫’、‘仓鼠’、‘鸟’、‘蛇’]
在处理较大数据时,这两种方法在性能方面是否存在差异?如果您使用的是ES2015,则扩展运算符是一种可行的方法。与其他方法相比,使用spread运算符时,代码看起来不那么冗长,也更干净。说到速度,我相信在这两种方法之间几乎没有什么可选择的。这两种方法都是Function.prototype.apply,当应用于大型阵列时,扩展语法可能会导致堆栈溢出:
让xs=新阵列(500000),
ys=[],zs;
xs.fill(“foo”);
试一试{
ys.push.apply(ys,xs);
}捕获(e){
log(“apply:,e.message)
}
试一试{
推送(…xs);
}捕获(e){
console.log(“传播:”,e.message)
}
zs=ys.concat(xs);
console.log(“concat:,zs.length)
除了,Array.prototype.concat
平均比Array spread操作符快至少1.4倍
请参见此处的结果:
您可以在您自己的浏览器和机器上运行测试:将问题解释为
,通常使用.push()作为示例,
它看起来应用速度[仅略]快一些(MS Edge除外,见下文)
这两种方法的动态调用函数的开销
function test() { console.log(arguments[arguments.length - 1]); }
var using = (new Array(200)).fill(null).map((e, i) => (i));
我在Chrome 71.0.3578.80(官方版本)(64位),
FF 63.0.3(64位)
,&Edge 42.17134.1.0
中进行了测试,这些都是我自己运行了几次后的结果。最初的结果总是向某个方向倾斜
正如您所看到的,Edge对apply
的实现似乎比它对..
的实现更好(但不要尝试在不同浏览器之间比较结果,我们无法从这些数据中判断Edge的apply
是否比其他浏览器更好,..
是否更差,或者两者兼而有之)。有鉴于此,除非您专门针对Edge,否则我会说使用
…
,就像它读起来更干净一样,特别是如果您需要将对象传递回应用以获得此
它也可能取决于数组的大小,所以就像@Jaromanda X
所说的那样,进行您自己的测试并更改200
,如果您需要真正确定的话
其他答案将该问题解释为,这对.push()更有利,特别是,并关注正在解决的“问题”,只是建议只使用.concat()
,这基本上是标准的为什么要这样做?
这会让一些来自谷歌的人感到厌烦,因为他们不想用.push()
(比如说,Math.max
,或者你自己的自定义函数)来寻找解决方案。我不知道他们的结论是怎么得出的,可能是糟糕的测试
Chrome 71.0.3578.80(官方版本)(64位)
,FF 63.0.3(64位)
,&Edge 42.17134.1.0
这是有意义的,因为concat()
复制数组,甚至不尝试使用相同的内存
关于“突变”的事情似乎没有任何根据;如果要覆盖旧数组,concat()
没有任何好处
不使用..
的唯一原因是堆栈溢出,我同意您不能使用..
或应用的其他答案
但是,即使在所有浏览器中,仅使用作为{push()}
的速度也差不多是concat()的两倍,而且不会溢出。
没有理由使用concat()
,除非需要保留旧数组。使用push将附加到现有数组,使用spread操作符创建副本
a=[1,2,3]
b=a
a=[...a, 4]
alert(b);
=>1,2,3
a=[1,2,3]
b=a
a.push(4)
alert(b);
=>1,2,3,4
推送。同时应用:
a=[1,2,3]
c=[4]
b=a
Array.prototype.push.apply(a,c)
alert(b);
=>1,2,3,4
康卡特是复制品
a=[1,2,3]
c=[4]
b=a
a=a.concat(c)
alert(b);
=>1,2,3
a=[1,2,3]
b=a
a.push(4)
alert(b);
通过引用是最好的,尤其是对于较大的阵列
“Spread operator”是一种快速复制方式,传统上可以通过以下方式进行复制:
a=[1,2,3]
b=[]
a.forEach(i=>b.push(i))
a.push(4)
alert(b);
=>1,2,3
a=[1,2,3]
b=a
a.push(4)
alert(b);
如果您需要副本,请使用spread操作符,这样做很快。或者使用@ftor指出的concat。如果没有,请使用推送。然而,请记住,有些情况下你不能变异。此外,使用这些函数中的任何一个,您都将获得浅拷贝,而不是深拷贝。对于深度复制,您将需要lodash。阅读更多信息:用户6445533的答案被接受为答案,但我觉得测试用例有点奇怪。这似乎不是通常应该如何使用扩展运算符
为什么不能像这样做:
let newPets = [...pets, ...wishlist]
它不会面临上述任何stackoverflow问题。
正如Hashbrown所提到的,它也可能给您带来性能上的好处
<>我也在学习ES6。对不起,如果我错了 定义“更大”的数据-firefox使用方法2看起来更慢。。。其他浏览器可能会更快。。。尝试您自己的基准测试如果您正在转换到ES5,Babel/TypeScript等很有可能会生成与pets.push.apply完全相同的代码。在任何情况下,性能差异影响应用程序速度的可能性都很小。为什么你会奇怪呢?在JS中,你可以向一个函数发送不确定数量的参数,但不能发送不确定数量的参数。根据当前会话可用堆栈大小,有一个限制