Para duplicar uma matriz em JavaScript: qual das opções a seguir é mais rápida de usar?
Método de fatia
var dup_array = original_array.slice();
For
ciclo
for(var i = 0, len = original_array.length; i < len; ++i)
dup_array[i] = original_array[i];
Sei que as duas maneiras fazem apenas uma cópia superficial : se original_array contiver referências a objetos, os objetos não serão clonados, mas apenas as referências serão copiadas e, portanto, as duas matrizes terão referências aos mesmos objetos. Mas este não é o objetivo desta questão.
Estou perguntando apenas sobre velocidade.
javascript
arrays
duplicates
copy
slice
Marco Demaio
fonte
fonte
Respostas:
Existem pelo menos 5 (!) Maneiras de clonar uma matriz:
Houve um encadeamento de BENCHMARKS , fornecendo as seguintes informações:
para navegadores intermitentes
slice()
é o método mais rápido,concat()
um pouco mais lento ewhile loop
2,4x mais lento.para outros navegadores
while loop
é o método mais rápido, pois esses navegadores não possuem otimizações internas paraslice
econcat
.Isso permanece verdadeiro em julho de 2016.
Abaixo estão alguns scripts simples que você pode copiar e colar no console do navegador e executar várias vezes para ver a imagem. Eles produzem milissegundos, quanto menor, melhor.
enquanto loop
fatia
Observe que esses métodos clonam o próprio objeto Array, mas o conteúdo do array é copiado por referência e não é profundamente clonado.
fonte
splice
e você ficará surpreso (enquanto ...)A.map(function(e){return e;});
Tecnicamente,
slice
é o caminho mais rápido. No entanto , é ainda mais rápido se você adicionar o0
índice inicial.é mais rápido que
http://jsperf.com/cloning-arrays/3
fonte
myArray.slice(0,myArray.length-1);
mais rápido quemyArray.slice(0);
?e quanto à es6 way?
fonte
[].concat(_slice.call(arguments))
arguments
vem ... Acho que sua saída do babel está confluindo alguns recursos diferentes. É mais provável que sejaarr2 = [].concat(arr1)
.arr2 = [].conact(arr1)
é diferente dearr2 = [...arr1]
.[...arr1]
A sintaxe converterá o furo emundefined
. Por exemploarr1 = Array(1); arr2 = [...arr1]; arr3 = [].concat(arr1); 0 in arr2 !== 0 in arr3
,.n = 1000*1000; start = + new Date(); a = Array(n); b = [...a]; console.log(new Date() - start); // 168
[{a: 'a', b: {c: 'c'}}]
. Sec
o valor de for alterado na matriz "duplicada", ele será alterado na matriz original, pois é apenas uma cópia referencial, não um clone.A maneira mais fácil de clonar profundamente Matriz ou Objeto:
fonte
undefined
ou nenhumfunction
s. Ambos serão convertidosnull
para você durante oJSON.stringify
processo. Outras estratégias, como(['cool','array']).slice()
não as alteram, mas também não clonam objetos profundamente dentro da matriz. Portanto, há uma troca.n = 1000*1000; start = + new Date(); a = Array(n); var b = JSON.parse(JSON.stringify(a)) console.log(new Date() - start); // 221
fonte
Eu montei uma demonstração rápida: http://jsbin.com/agugo3/edit
Meus resultados no Internet Explorer 8 são 156, 782 e 750, o que indicaria que
slice
é muito mais rápido nesse caso.fonte
a.map(e => e)
é outra alternativa para este trabalho. A partir de hoje,.map()
é muito rápido (quase tão rápido quanto.slice(0)
) no Firefox, mas não no Chrome.Por outro lado, se uma matriz é multi-dimensional, uma vez que as matrizes são objectos e objectos são tipos de referência, nenhum dos métodos ou fatia concat será uma cura ... Portanto, uma forma adequada de clonagem de uma matriz é uma invenção de
Array.prototype.clone()
quanto segue.fonte
Way A maneira mais rápida de clonar uma matriz
Eu criei essa função de utilitário muito simples para testar o tempo necessário para clonar uma matriz. Não é 100% confiável, no entanto, pode fornecer uma ideia geral sobre quanto tempo leva para clonar uma matriz existente:
E testou uma abordagem diferente:
UPDATE :
Nota: dentre todas, a única maneira de clonar profundamente uma matriz é usando
JSON.parse(JSON.stringify(arr))
.Dito isto, não use o acima se sua matriz pode incluir funções, pois ela retornará
null
.Obrigado @ GilEpshtain por esta atualização .
fonte
arr => arr.slice()
seja o mais rápido.JSON.parse(JSON.stringify([function(){}]))
irá produzir[null]
[...arr]
com4.653076171875ms
no Chrome e8.565ms
no Safari. O segundo jejum no Chrome é a função de fatiaarr.slice()
com6.162109375ms
e no Safari o segundo é[].concat(arr)
com13.018ms
.Dê uma olhada no: link . Não se trata de velocidade, mas de conforto. Além disso, como você pode ver, você só pode usar a fatia (0) em tipos primitivos .
Para fazer uma cópia independente de uma matriz em vez de uma cópia da referência a ela, você pode usar o método de fatia da matriz.
Exemplo:
Fonte: link
fonte
for
loop da pergunta.Como o @Dan disse: "Esta resposta fica desatualizada rapidamente. Use benchmarks para verificar a situação real", há uma resposta específica do jsperf que não teve uma resposta por si só: enquanto :
teve 960.589 ops / s com o
a.concat()
segundo colocado em 578.129 ops / s, que é de 60%.Este é o último Firefox (40) 64 bits.
A @aleclarson criou uma nova referência mais confiável.
fonte
Maneira ECMAScript 2015 com o
Spread
operador:Exemplos básicos:
Experimente no console do navegador:
Referências
fonte
Depende do navegador. Se você procurar na postagem do blog Array.prototype.slice x criação manual de matriz , há um guia aproximado para o desempenho de cada uma:
Resultados:
fonte
arguments
não é uma matriz adequada e ele está usandocall
para forçarslice
a execução na coleção. os resultados podem ser enganosos.Existe uma solução muito mais limpa:
A verificação do comprimento é necessária, porque o
Array
construtor se comporta de maneira diferente quando é chamado com exatamente um argumento.fonte
splice()
, talvez. Mas, na verdade, aplique e isso é tudo, menos intuitivo.Array.of
e ignorar o comprimento:Array.of.apply(Array, array)
Lembre-se de que .slice () não funcionará para matrizes bidimensionais. Você precisará de uma função como esta:
fonte
Depende do comprimento da matriz. Se o comprimento da matriz for <= 1.000.000, os métodos
slice
econcat
levarão aproximadamente o mesmo tempo. Mas quando você fornece uma faixa maior, oconcat
método vence.Por exemplo, tente este código:
Se você definir o comprimento da matriz original como 1.000.000, o
slice
método e oconcat
método levarão aproximadamente o mesmo tempo (3 a 4 ms, dependendo dos números aleatórios).Se você definir o comprimento da matriz original como 10.000.000, o
slice
método terá mais de 60 ms e oconcat
método terá mais de 20 ms.fonte
dup.push
está no erradoa5
, em vezdup[i] =
deve ser usadoUma solução simples:
fonte
Portanto, para evitar que esses cenários aconteçam, use
fonte
cloneNums[0][0]
no seu exemplo propagou a alteração paranums[0][0]
- mas isso é porque elenums[0][0]
é efetivamente um objeto cuja referência é copiadacloneNums
pelo operador de propagação. Tudo o que quer dizer, esse comportamento não afetará o código onde estamos copiando por valor (int, string etc literais).Hora de referência!
Meus resultados:
Chrome (mecanismo V8):
Firefox (mecanismo SpiderMonkey):
fonte
Maneiras rápidas de duplicar uma matriz em JavaScript na ordem:
#1: array1copy = [...array1];
#2: array1copy = array1.slice(0);
#3: array1copy = array1.slice();
Se os objetos da matriz contiverem algum conteúdo JSON não serializável (funções, Number.POSITIVE_INFINITY etc.) melhor para usar
array1copy = JSON.parse(JSON.stringify(array1))
fonte
Você pode seguir este código. Clone de matriz de maneira imutável. Essa é a maneira perfeita de clonar matrizes
fonte
No ES6, você pode simplesmente utilizar a sintaxe do Spread .
Exemplo:
Observe que o operador spread gera uma matriz completamente nova, portanto, modificar uma não afetará a outra.
Exemplo:
fonte