在处理数组时,使用扩展语法(...)和push.apply之间的区别

Net*_*yth 21 javascript arrays apply ecmascript-6 spread-syntax

我有两个数组,

const pets = ["dog", "cat", "hamster"]

const wishlist = ["bird", "snake"]
Run Code Online (Sandbox Code Playgroud)

我要附加wishlistpets,可以使用两种方法来完成,

方法1:

pets.push.apply(pets,wishlist)
Run Code Online (Sandbox Code Playgroud)

结果如下: [ 'dog', 'cat', 'hamster', 'bird', 'snake' ]

方法2:

pets.push(...wishlist)
Run Code Online (Sandbox Code Playgroud)

这也导致: [ 'dog', 'cat', 'hamster', 'bird', 'snake' ]

当我处理更大的数据时,这两种方法在性能方面是否存在差异?

小智 19

Function.prototype.apply当应用于大型数组时,两者和扩展语法都可能导致堆栈溢出:

let xs = new Array(500000),
 ys = [], zs;

xs.fill("foo");

try {
  ys.push.apply(ys, xs);
} catch (e) {
  console.log("apply:", e.message)
}

try {
  ys.push(...xs);
} catch (e) {
  console.log("spread:", e.message)
}

zs = ys.concat(xs);
console.log("concat:", zs.length)
Run Code Online (Sandbox Code Playgroud)

Array.prototype.concat改用.除了避免堆栈溢出之外concat,还具有避免突变的优点.突变被认为是有害的,因为它们可能导致微妙的副作用.

但这不是教条.如果您正在使用函数作用域并执行突变以提高性能并减少垃圾回收,则可以执行突变,只要它们在父作用域中不可见即可.


Has*_*own 5

对于附加到大型数组,扩展运算符要快得多。我不知道他们@ftor是如何@Liau Jian Jie得出结论的,可能是糟糕的测试。

检测结果 Chrome 71.0.3578.80 (Official Build) (64-bit), FF 63.0.3 (64-bit), &Edge 42.17134.1.0

这是有道理的,因为concat()创建了数组的副本,甚至不尝试使用相同的内存。

关于“突变”的事情似乎没有任何根据;如果您覆盖旧数组,concat()则没有任何好处。

不使用的唯一原因...是堆栈溢出,我同意您不能使用...或的apply其他答案。
但即便如此,仅使用 a 的速度for {push()}或多或少是所有浏览器中的两倍concat(),并且不会溢出。除非您需要保留旧数组,
否则 没有理由使用。concat()


Rik*_*Rik 5

通过推送,您可以追加到现有数组,通过扩展运算符,您可以创建一个副本。

a=[1,2,3]
b=a
a=[...a, 4]
alert(b);
Run Code Online (Sandbox Code Playgroud)

=> 1, 2, 3

 a=[1,2,3]
b=a
a.push(4)
alert(b);
Run Code Online (Sandbox Code Playgroud)

=> 1, 2, 3, 4

也推.应用:

a=[1,2,3]
c=[4]
b=a
Array.prototype.push.apply(a,c)
alert(b);
Run Code Online (Sandbox Code Playgroud)

=> 1, 2, 3, 4

concat 是一个副本

a=[1,2,3]
c=[4]
b=a
a=a.concat(c)
alert(b);
Run Code Online (Sandbox Code Playgroud)

=> 1, 2, 3

优选通过引用,特别是对于较大的阵列。

扩展运算符是一种快速进行复制的方法,传统上是通过以下方式完成的:

a=[1,2,3]
b=[]
a.forEach(i=>b.push(i))
a.push(4)
alert(b);
Run Code Online (Sandbox Code Playgroud)

=> 1, 2, 3

如果您需要副本,请使用扩展运算符,速度很快。或者使用 @ftor 指出的 concat。如果没有,请使用推送。但请记住,在某些情况下您无法进行变异。此外,使用这些函数中的任何一个,您都将获得浅拷贝,而不是深拷贝。对于深度复制,您将需要 lodash。在这里阅读更多信息: https: //slemgrim.com/mutate-or-not-to-mutate/


小智 -2

如果您使用 ES2015,那么扩展运算符就是最佳选择。与其他方法相比,使用扩展运算符,您的代码看起来不那么冗长且干净得多。当谈到速度时,我相信这两种方法之间没有什么可供选择的。