Ao copiar uma matriz em JavaScript para outra matriz:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
Percebi que isso arr2
se refere à mesma matriz que arr1
, em vez de uma nova matriz independente. Como copiar a matriz para obter duas matrizes independentes?
javascript
arrays
Dan
fonte
fonte
slice
esplice
operações interessantes e novo operador de propagação eArray.from
implementação muito mais lenta. Veja perfjs.fnfovar arr2 = arr1.splice();
a cópia profunda, mas esta técnica não vai funcionar se os elementos em sua matriz contêm estruturas literais (ie[]
ou{}
) ou objetos de protótipo (ou sejafunction () {}
,new
, etc). Veja minha resposta abaixo para obter mais soluções.let arr2 = [...arr1];
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...Respostas:
Usa isto:
Basicamente, a
slice()
operação clona a matriz e retorna uma referência a uma nova matriz.Observe também que:
Para referências, seqüências de caracteres e números (e não o objeto real),
slice()
copia as referências do objeto para a nova matriz. Tanto a matriz original quanto a nova se referem ao mesmo objeto. Se um objeto referenciado for alterado, as alterações serão visíveis para as matrizes nova e original.Primitivas como seqüências de caracteres e números são imutáveis, portanto, alterações na sequência ou no número são impossíveis.
fonte
.slice()
com.splice()
, o que fornece uma matriz vazia. Grande diferença.Em Javascript, as técnicas de cópia em profundidade dependem dos elementos em uma matriz. Vamos começar por aí.
Três tipos de elementos
Os elementos podem ser: valores literais, estruturas literais ou protótipos.
A partir desses elementos, podemos criar três tipos de matrizes.
As técnicas de cópia profunda dependem dos três tipos de matriz
Com base nos tipos de elementos da matriz, podemos usar várias técnicas para copiar em profundidade.
Matriz de valores de literais (de tipo 1)
O
[...myArray]
,myArray.splice(0)
,myArray.slice()
, emyArray.concat()
técnicas podem ser utilizadas para matrizes de cópia profundos com valores literais (booleano, número, e de cordas) apenas; onde o operador Spread[...myArray]
tem o melhor desempenho ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).Matriz de valores literais (tipo1) e estruturas literais (tipo2)
A
JSON.parse(JSON.stringify(myArray))
técnica pode ser usada para copiar profundamente valores literais (booleano, número, sequência) e estruturas literais (matriz, objeto), mas não objetos de protótipo.Todas as matrizes (tipo1, tipo2, tipo3)
A
$.extend(myArray)
técnica jQuery pode ser usada para copiar em profundidade todos os tipos de matriz. Bibliotecas como Underscore e Lo-dash oferecem funções de cópia profunda semelhantes ao jQuery$.extend()
, mas com desempenho inferior. Surpreendentemente,$.extend()
tem desempenho superior àJSON.parse(JSON.stringify(myArray))
técnica http://jsperf.com/js-deep-copy/15 .E para os desenvolvedores que evitam as bibliotecas de terceiros (como o jQuery), você pode usar a seguinte função personalizada; que tem um desempenho superior a $ .extend e copia em profundidade todas as matrizes.
Então, para responder à pergunta ...
Questão
Responda
Como
arr1
é uma matriz de valores literais (booleano, número ou string), você pode usar qualquer técnica de cópia em profundidade discutida acima, em que o operador de spread...
tenha o melhor desempenho.fonte
arr1
. É muito raro que seja esse o caso. Usandosplice
obliteradosarr1
, isso não é uma cópia. O usoJSON
falhará se algum dos valores da matriz for Funções ou possuir protótipos (como aDate
).[0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]
e qualquer outra matriz.Você pode usar spreads de matriz
...
para copiar matrizes.const itemsCopy = [...items];
Além disso, se desejar criar uma nova matriz com a existente, faça parte dela:
As propagações de matriz agora são suportadas em todos os principais navegadores, mas se você precisar de suporte mais antigo, use typescript ou babel e compile no ES5.
Mais informações sobre spreads
fonte
Não é necessário jQuery ... Exemplo de trabalho
Isso copia a matriz da posição inicial
0
até o final da matriz.É importante observar que funcionará conforme o esperado para tipos primitivos (sequência, número etc.) e também explicar o comportamento esperado para tipos de referência ...
Se você tiver uma matriz de tipos de referência, digamos do tipo
Object
. A matriz será copiada, mas ambas as matrizes conterão referências às mesmasObject
. Portanto, nesse caso, parece que a matriz é copiada por referência, mesmo que a matriz seja realmente copiada.fonte
var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
Uma alternativa para
slice
éconcat
, que pode ser usada de duas maneiras. O primeiro deles é talvez mais legível, pois o comportamento pretendido é muito claro:O segundo método é:
Cohen (nos comentários) apontou que este último método tem melhor desempenho .
A maneira como isso funciona é que o
concat
método cria uma nova matriz que consiste nos elementos no objeto no qual é chamado, seguido pelos elementos de quaisquer matrizes passadas a ele como argumentos. Portanto, quando nenhum argumento é passado, ele simplesmente copia a matriz.Lee Penkman, também nos comentários, assinala que, se há uma chance
array1
éundefined
, você pode retornar um array vazio como se segue:Ou, para o segundo método:
Note que você também pode fazer isso com
slice
:var array2 = (array1 || []).slice();
.fonte
[].concat(array1)
retornará,[array1]
por exemplo, se não for definido, você receberá[undefined]
. Às vezes eu façovar array2 = [].concat(array1 || []);
Foi assim que fiz depois de tentar várias abordagens:
Isso criará uma nova cópia profunda não relacionada à primeira (não uma cópia superficial).
Além disso, obviamente, isso não clonará eventos e funções, mas o bom é que você pode fazê-lo em uma linha e pode ser usado para qualquer tipo de objeto (matrizes, strings, números, objetos ...)
fonte
Date
, ou de fato, qualquer coisa que tenha um protótipo. Além disso,undefined
s são convertidos emnull
s.Alguns dos métodos mencionados funcionam bem ao trabalhar com tipos de dados simples, como número ou string, mas quando a matriz contém outros objetos, esses métodos falham. Quando tentamos passar qualquer objeto de uma matriz para outra, ele é passado como referência, não como objeto.
Adicione o seguinte código ao seu arquivo JavaScript:
E simplesmente use
Vai funcionar.
fonte
.slice()
ainda funciona bem mesmo se você tiver objetos em sua matriz: jsfiddle.net/edelman/k525gA partir do ES2015,
fonte
Pessoalmente, acho que o Array.from é uma solução mais legível. A propósito, apenas tome cuidado com o suporte ao navegador.
fonte
.slice()
solução é completamente não intuitiva. Obrigado por isso.Importante!
A maioria das respostas aqui funciona para casos particulares .
Se você não se importa com objetos profundos / aninhados e adereços, use ( ES6 ):
let clonedArray = [...array]
mas se você quiser fazer um clone profundo, use isso:
let cloneArray = JSON.parse(JSON.stringify(array))
Para usuários do lodash:
let clonedArray = _.clone(array)
documentaçãoe
let clonedArray = _.cloneDeep(array)
documentaçãofonte
Se você estiver em um ambiente do ECMAScript 6 , usando o Operador de propagação, poderá fazê-lo desta maneira:
fonte
Adicionando à solução de array.slice (); esteja ciente de que se você tiver sub-matrizes multidimensionais de matriz serão copiadas por referências. O que você pode fazer é fazer um loop e fatiar () cada sub-matriz individualmente
o mesmo acontece com a matriz de objetos, eles serão copiados por referência, você deve copiá-los manualmente
fonte
Os valores primitivos sempre passam pelo seu valor (copiado). Os valores compostos, no entanto, são passados por referência.
Então, como copiamos essa arr?
Copiar uma matriz no ES6
Copiar n Matriz no ES5
Por que deixar arrCopy = arr não passar por valor?
Passar uma variável para outra em valores compostos, como Objeto / Matriz, se comporta de maneira diferente. Usando um operador asign em valores de copand, passamos referência a um objeto. É por isso que o valor de ambas as matrizes está mudando ao remover / adicionar elementos arr.
Exceções:
Ao atribuir um novo valor à variável, você está alterando a própria referência e ela não afeta o Objeto / Matriz original.
consulte Mais informação
fonte
Como sabemos em matrizes e objetos Javascript são por referência, mas de que maneiras podemos copiar a matriz sem alterar a matriz original posteriormente?
Aqui estão algumas maneiras de fazer isso:
Imagine que temos essa matriz em seu código:
1) Fazendo loop na matriz em uma função e retornando uma nova matriz, assim:
2) Usando o método de fatia, fatia é para fatiar parte da matriz, fatiará parte de sua matriz sem tocar no original, na fatia, se não especificar o início e o fim da matriz, fatiará todo matriz e basicamente fazer uma cópia completa da matriz, para que possamos dizer facilmente:
3) Também entre em contato com o método, isto é para mesclar duas matrizes, mas podemos apenas especificar uma das matrizes e, basicamente, fazer uma cópia dos valores na nova matriz contatada:
4) Também método stringify e parse, não é recomendado, mas pode ser uma maneira fácil de copiar Array e Objetos:
5) Método Array.from, isso não é amplamente suportado, antes de usar, verifique o suporte em diferentes navegadores:
6) Maneira ECMA6, também não totalmente suportada, mas o babelJs pode ajudá-lo se você deseja transpilar:
fonte
Agora você pode executar qualquer um dos seguintes procedimentos para fazer uma cópia de uma matriz.
OU
OU
OU
OU
Agora, se eu mudar um,
Então, a é [1,2,3,5], mas b ainda é [1,2,3], pois possui referência diferente.
Mas eu acho que, em todos os métodos acima de Array.from, é melhor e feito principalmente para copiar uma matriz.
fonte
Eu pessoalmente prefiro assim:
fonte
No meu caso particular, eu precisava garantir que a matriz permanecesse intacta, de modo que funcionou para mim:
fonte
Faça uma cópia da matriz / objeto multidimensional:
Obrigado a James Padolsey por esta função.
Fonte: Aqui
fonte
Dan, não há necessidade de usar truques sofisticados. Tudo o que você precisa fazer é copiar o arr1 fazendo isso.
Agora
arr1
earr2
existem duas variáveis de matriz diferentes armazenadas em pilhas separadas. Verifique isso no jsfiddle .fonte
var arr2 = [arr1];
).Quando queremos copiar um array usando o operador de atribuição (
=
), ele não cria uma cópia, apenas copia o ponteiro / referência ao array. Por exemplo:Frequentemente, quando transformamos dados, queremos manter intacta nossa estrutura de dados inicial (por exemplo, Matriz). Fazemos isso fazendo uma cópia exata de nossa matriz para que esta possa ser transformada enquanto a inicial permanece intacta.
Maneiras de copiar uma matriz:
Tenha cuidado quando matrizes ou objetos estiverem aninhados !:
Quando matrizes são aninhadas, os valores são copiados por referência. Aqui está um exemplo de como isso pode levar a problemas:
Portanto, não use esses métodos quando houver objetos ou matrizes em sua matriz que você deseja copiar. ou seja, use esses métodos apenas em matrizes de primitivos.
Se você deseja fazer um deepclone de uma matriz javascript usada
JSON.parse
em conjunto comJSON.stringify
, desta forma:Desempenho da cópia:
Então, qual escolhemos para um desempenho ideal? Acontece que, o método mais detalhado, o
for
loop tem o melhor desempenho. Use ofor
loop para cópias realmente intensivas da CPU (grandes / muitas matrizes).Depois disso, o
.slice()
método também possui um desempenho decente e também é menos detalhado e mais fácil para o programador implementar. Sugiro usar.slice()
para a cópia diária de matrizes que não consomem muita CPU. Evite também usarJSON.parse(JSON.stringify(arr))
(muita sobrecarga) se nenhum clone profundo for necessário e o desempenho for um problema.Teste de desempenho da fonte
fonte
Se sua matriz contiver elementos do tipo de dados primitivo , como int, char ou string, etc. , você poderá usar um desses métodos que retornará uma cópia da matriz original, como operador .slice () ou .map () ou spread ( graças ao ES6).
ou
ou
MAS, se a sua matriz contiver elementos complexos , como objetos (ou matrizes) ou mais objetos aninhados , você deverá certificar-se de que está fazendo uma cópia de todos os elementos do nível superior ao último nível, além da referência interna objetos serão usados e isso significa que alterar valores em object_elements em new_array ainda afetará o old_array. Você pode chamar esse método de cópia em cada nível como fazer uma CÓPIA PROFUNDA da matriz_ antiga.
Para cópias profundas, você pode usar os métodos acima mencionados para tipos de dados primitivos em cada nível, dependendo do tipo de dados, ou pode usar esse método caro (mencionado abaixo) para fazer uma cópia profunda sem fazer muito trabalho.
Existem muitos outros métodos por aí que você pode usar dependendo de seus requisitos. Mencionei apenas alguns deles por fornecer uma idéia geral do que acontece quando tentamos copiar um array para outro por valor .
fonte
Se você deseja fazer uma nova cópia de um objeto ou matriz, copie explicitamente as propriedades do objeto ou dos elementos da matriz, por exemplo:
Você pode procurar mais informações no Google sobre valores primitivos imutáveis e referências a objetos mutáveis.
fonte
O uso da cópia profunda do jQuery pode ser feito da seguinte maneira:
fonte
Você também pode usar o operador de spread ES6 para copiar a matriz
fonte
Aqui estão mais algumas maneiras de copiar:
fonte
Você pode usar o ES6 com o Opeartor espalhado, é mais simples.
Existem limitações .. verifique os documentos Spread syntax @ mozilla
fonte
Exemplos rápidos:
fonte
Aqui está uma variante:
fonte
toSource
não é padrão e não funcionará no Chrome, por exemplo.Há o recém-introduzido
Array.from
, mas infelizmente, até o momento em que este artigo foi escrito, ele era suportado apenas nas versões recentes do Firefox (32 e superior). Pode ser simplesmente usado da seguinte maneira:Referência: Aqui
Ou
Array.prototype.map
pode ser usado com uma função de identidade:Referência: Aqui
fonte
Array.from
, que agora é suportado em todos os principais navegadores, exceto no Internet Explorer ( origem ). .Array.from
que os dados serão alterados, não fornece cópia / clonagem profunda.Para matriz ES6 contendo objetos
fonte