... onde cada objeto também tem referências a outros objetos na mesma matriz?
Quando me deparei com esse problema, pensei em algo como
var clonedNodesArray = nodesArray.clone()
existiria e procurou informações sobre como clonar objetos em javascript. Eu encontrei uma pergunta no StackOverflow (respondida pelo mesmo @JohnResig) e ele apontou que com o jQuery você poderia fazer
var clonedNodesArray = jQuery.extend({}, nodesArray);
clonar um objeto. Eu tentei isso, porém, isso apenas copia as referências dos objetos na matriz. Então se eu
nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"
o valor de nodesArray [0] e clonedNodesArray [0] será "verde". Então eu tentei
var clonedNodesArray = jQuery.extend(true, {}, nodesArray);
que copia profundamente um objeto, mas recebi mensagens de " muita recursão " e " controle da pilha excedente " do Firebug e do Opera Dragonfly, respectivamente.
Como você faria? Isso é algo que nem deveria ser feito? Existe uma maneira reutilizável de fazer isso em Javascript?
fonte
Desde que seus objetos contenham conteúdo serializável em JSON (sem funções, não
Number.POSITIVE_INFINITY
etc.), não há necessidade de loops para clonar matrizes ou objetos. Aqui está uma solução de uma linha pura de baunilha.Para resumir os comentários abaixo, a principal vantagem dessa abordagem é que ela também clona o conteúdo da matriz, não apenas a matriz em si. As principais desvantagens são o limite de trabalhar apenas em conteúdo serializável em JSON e o desempenho (que é significativamente pior do que uma
slice
abordagem baseada).fonte
null
eundefined
serão problemas, pois o JSON não os suporta). Além disso, é uma operação muito menos eficiente queold_array.slice(0);
, que deve funcionar melhor e mais rapidamente.Resolvi a clonagem de uma matriz de objetos com Object.assign
ou ainda mais curto com sintaxe de propagação
fonte
{}
pornew Dinosaur()
.Se tudo o que você precisa é de uma cópia superficial, uma maneira realmente fácil é:
fonte
0
, você pode apenas chamar.slice()
pelo menos em cromo de qualquer maneiraslice
será uma nova matriz, mas conterá as referências aos objetos originais da matriz.A melhor e mais atualizada maneira de fazer esse clone é a seguinte:
Usando o
...
operador de expansão ES6.Aqui está o exemplo mais simples:
Dessa forma, distribuímos a matriz em valores individuais e a colocamos em uma nova matriz com o operador [].
Aqui está um exemplo mais longo que mostra as diferentes maneiras como funciona:
fonte
Isso funciona para mim:
E se você precisar de uma cópia profunda dos objetos na matriz:
fonte
fonte
JSON.parse(JSON.stringify(origArray));
JSON.parse(JSON.stringify(origArray));
é definitivamente a solução mais simples.O mapa criará uma nova matriz a partir da antiga (sem referência à antiga) e, dentro do mapa, você criará um novo objeto e iterará sobre as propriedades (chaves) e atribuirá valores do objeto antigo da Matriz às propriedades correspondentes do novo objeto.
Isso criará exatamente a mesma matriz de objetos.
fonte
Eu posso ter uma maneira simples de fazer isso sem ter que fazer uma recursão dolorosa e sem conhecer todos os detalhes do objeto em questão. Usando o jQuery, basta converter seu objeto em JSON usando o jQuery
$.toJSON(myObjectArray)
, em seguida, pegue sua string JSON e avalie-a novamente em um objeto. BAM! Feito e feito! Problema resolvido. :)fonte
eval
.eval()
. É um risco de segurança.Estou respondendo a essa pergunta porque não parece haver uma solução simples e explícita para o problema de "clonar uma matriz de objetos em Javascript":
Essa solução itera os valores da matriz, depois as chaves do objeto, salvando-as em um novo objeto e, em seguida, enviando esse novo objeto para uma nova matriz.
Veja jsfiddle . Nota: um simples
.slice()
ou[].concat()
não é suficiente para os objetos dentro da matriz.fonte
A extensão do JQuery está funcionando bem, basta especificar que você está clonando uma matriz em vez de um objeto ( observe o parâmetro [] em vez de {} como parâmetro no método extend ):
fonte
Este método é muito simples e você pode modificar seu clone sem modificar a matriz original.
fonte
[...oldArray]
eoldArray.slice(0)
fazer uma rasa copiar um profundo nível. Portanto, isso é super útil, mas não um clone profundo e real.lodash.clonedeep
partir da npmComo Daniel Lew mencionou, os gráficos cíclicos têm alguns problemas. Se eu tivesse esse problema, adicionaria
clone()
métodos especiais aos objetos problemáticos ou lembraria quais objetos eu já copiei.Eu faria isso com uma variável
copyCount
que aumenta em 1 toda vez que você copia seu código. Um objeto que tem um valor mais baixocopyCount
processo de cópia que o atual é copiado. Caso contrário, a cópia, que já existe, deve ser referenciada. Isso torna necessário vincular o original à sua cópia.Ainda existe um problema: Memória. Se você tiver essa referência de um objeto para outro, é provável que o navegador não consiga liberar esses objetos, pois eles sempre são referenciados de algum lugar. Você precisaria fazer uma segunda passagem para definir todas as referências de cópia para Nulo. (Se você fizer isso, não precisaria ter um,
copyCount
mas um booleanoisCopied
seria suficiente, pois você pode redefinir o valor na segunda passagem.)fonte
Array.slice pode ser usado para copiar uma matriz ou parte de uma matriz. Http://www.devguru.com/Technologies/Ecmascript/Quickref/Slice.html Isso funcionaria com seqüências e números .. - alterando uma sequência em uma matriz não afetaria a outra - mas os objetos ainda são copiados apenas por referência; portanto, as alterações nos objetos referenciados em uma matriz afetariam a outra matriz.
Aqui está um exemplo de um gerenciador de desfazer JavaScript que pode ser útil para isso: http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx
fonte
Minha abordagem:
fornece um clone agradável, limpo e profundo da matriz original - sem nenhum dos objetos referenciados de volta ao original :-)
fonte
O lodash tem
cloneDeep
função para esses propósitos:fonte
Se você deseja implementar o clone profundo, use JSON.parse (JSON.stringify (your {} ou []))
fonte
esqueça eval () (é o recurso mais mal utilizado do JS e torna o código lento) e slice (0) (funciona apenas para tipos de dados simples)
Esta é a melhor solução para mim:
fonte
Fiquei bastante frustrado com esse problema. Aparentemente, o problema surge quando você envia uma matriz genérica para o método $ .extend. Portanto, para corrigi-lo, adicionei uma pequena verificação e funciona perfeitamente com matrizes genéricas, matrizes jQuery e quaisquer objetos.
Invoque usando:
fonte
Isso copia profundamente matrizes, objetos, valores nulos e outros valores escalares e também copia profundamente quaisquer propriedades em funções não nativas (o que é bastante incomum, mas possível). (Por questões de eficiência, não tentamos copiar propriedades não numéricas em matrizes.)
fonte
Eu uso o novo método ECMAScript 6 Object.assign :
o primeiro argumento desse método é a matriz a ser atualizada; passamos um objeto vazio porque queremos ter um novo objeto.
também podemos usar esta sintaxe, que é a mesma, mas mais curta:
fonte
Podemos inventar um método simples de matriz recursiva para clonar matrizes multidimensionais. Enquanto os objetos nas matrizes aninhadas mantêm sua referência aos objetos correspondentes na matriz de origem, as matrizes não.
fonte
No JavaScript, a cópia da matriz e do objeto altera os valores de origem; portanto, a cópia profunda é a solução para isso.
Uma cópia profunda significa, na verdade, criar uma nova matriz e copiar os valores, pois o que quer que aconteça nunca afetará a origem.
JSON.parse
eJSON.stringify
é a melhor e mais simples maneira de copiar em profundidade. OJSON.stringify()
método converte um valor JavaScript em uma string JSON. OJSON.parse()
método analisa uma string JSON, construindo o valor ou o objeto JavaScript descrito pela string.// Deep Clone
Para mais detalhes: Leia aqui
fonte
com jQuery:
fonte
O código a seguir executará recursivamente uma cópia profunda de objetos e matriz :
Fonte
fonte
arguments.callee
não está disponível no modo estrito e tem problemas de desempenho caso contrário.Algumas maneiras elegantes de clonagem profunda em javascript
https://mootools.net/core/docs/1.6.0/Types/Object
https://scotch.io/bar-talk/copying-objects-in-javascript
1) Um método Javascript de baunilha para clonagem de objetos
2) Uma exploração inteligente da biblioteca JSON para clonar objetos profundamente
3) Usando a função $ .extend () do jQuery
4) Usando a função clone () do Mootools para clonar objetos
fonte
Eu acho que conseguiu escrever um método genérico de clonagem profunda de qualquer estrutura JavaScript usando principalmente,
Object.create
que é suportada em todos os navegadores modernos. O código é assim:fonte
Object.create
trataráitem
como o protótipo do objeto, mas isso é diferente da clonagem. Seitem
for modificado, as alterações serão refletidas em seu "clone" e vice-versa. Essa abordagem não funciona.Para clonar os objetos, eu sugeria o ECMAScript 6
reduce()
:Mas, francamente, eu gosto ainda mais da resposta do @dinodsaurus. Estou apenas colocando esta versão aqui como outra opção, mas pessoalmente vou usar
map()
como sugerido por @dinodsaurus.fonte
Dependendo se você tem Sublinhado ou Babel, aqui está uma referência da maneira diferente de clonar profundamente uma matriz.
https://jsperf.com/object-rest-spread-vs-clone/2
Parece que babel é o mais rápido.
fonte
fonte