uso - vector in javascript




Copia matrice per valore (19)

Quando si copia un array in JavaScript in un altro array:

var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d');  //Now, arr1 = ['a','b','c','d']

Ho capito che arr2 riferisce allo stesso array di arr1 , piuttosto che a un nuovo array indipendente. Come posso copiare l'array per ottenere due array indipendenti?


È inoltre possibile utilizzare l'operatore di diffusione ES6 per copiare la matrice

var arr=[2,3,4,5];
var copyArr=[...arr];

È possibile utilizzare ES6 con Opeartor steso, è più semplice.

arr2 = [...arr1];

Esistono dei limiti.chiesta di documenti. Spiegare la sintassi @ mozilla


Aggiunta alla soluzione di array.slice (); essere consapevoli del fatto che se si dispone di array multidimensionali, i sub-array verranno copiati mediante riferimenti. Quello che puoi fare è fare un loop e slice () ogni sub-array individualmente

var arr = [[1,1,1],[2,2,2],[3,3,3]];
var arr2 = arr.slice();

arr2[0][1] = 55;
console.log(arr2[0][1]);
console.log(arr[0][1]);

function arrCpy(arrSrc, arrDis){
 for(elm in arrSrc){
  arrDis.push(arrSrc[elm].slice());
}
}

var arr3=[];
arrCpy(arr,arr3);

arr3[1][1] = 77;

console.log(arr3[1][1]);
console.log(arr[1][1]);

le stesse cose vanno alla schiera di oggetti, saranno copiati per riferimento, è necessario copiarli manualmente


Alcuni dei metodi menzionati funzionano bene quando si lavora con tipi di dati semplici come numero o stringa, ma quando l'array contiene altri oggetti questi metodi falliscono. Quando proviamo a passare qualsiasi oggetto da una matrice all'altra viene passato come riferimento, non come oggetto.

Aggiungi il seguente codice nel tuo file JavaScript:

Object.prototype.clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (i in this) {
        if (i == 'clone') 
            continue;
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        } 
        else 
            newObj[i] = this[i]
    } return newObj;
};

E semplicemente usa

var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()

Funzionerà.


Come sappiamo, le matrici e gli oggetti Javascript sono per riferimento, ma in che modo possiamo copiare l'array senza modificare l'array originale più tardi?

Ecco alcuni modi per farlo:

Immagina di avere questo array nel tuo codice:

var arr = [1, 2, 3, 4, 5];

1) Fare il ciclo attraverso l'array in una funzione e restituire un nuovo array, come questo:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

2) Usando il metodo slice, slice serve per affettare una parte dell'array, affetterà alcune parti dell'array senza toccare l'originale, nella slice, se non specifichi l'inizio e la fine dell'array, esso troncerà l'intero array e fondamentalmente fanno una copia completa dell'array, quindi possiamo facilmente dire:

var arr2 = arr.slice(); // make a copy of the original array

3) Anche metodo di contatto, questo è per unire due array, ma possiamo solo specificare uno degli array e quindi questo fondamentalmente fare una copia dei valori nel nuovo array contattato:

var arr2 = arr.concat();

4) Stringify e analizza anche il metodo, non è raccomandato, ma può essere un modo semplice per copiare array e oggetti:

var arr2 = JSON.parse(JSON.stringify(arr));

5) Metodo Array.from, questo non è ampiamente supportato, prima dell'uso controllare il supporto in diversi browser:

const arr2 = Array.from(arr);

6) ECMA6, anche non completamente supportato, ma BabelJs può aiutarti se vuoi traspolare:

const arr2 = [...arr];

Crea una copia di array / oggetto multidimensionale:

function deepCopy(obj) {
   if (Object.prototype.toString.call(obj) === '[object Array]') {
      var out = [], i = 0, len = obj.length;
      for ( ; i < len; i++ ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   if (typeof obj === 'object') {
      var out = {}, i;
      for ( i in obj ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   return obj;
}

Grazie a James Padolsey per questa funzione.

Fonte: Here


Dan, non c'è bisogno di usare trucchi fantasiosi. Tutto ciò che devi fare è fare una copia di arr1 facendo questo.

var arr2 = new Array(arr1);

Ora arr1 e arr2 sono due diverse variabili di matrice memorizzate in stack separati. Dai un'occhiata a jsfiddle .


Ecco alcuni altri modi per copiare:

const array = [1,2,3,4];

const arrayCopy1 = Object.values(array);
const arrayCopy2 = Object.assign([], array);
const arrayCopy3 = array.map(i => i);
const arrayCopy4 = Array.of(...array );


In Javascript, le tecniche di copia profonda dipendono dagli elementi di un array.
Iniziamo da lì.

Tre tipi di elementi

Gli elementi possono essere: valori letterali, strutture letterali o prototipi.

// Literal values (type1)
var booleanLiteral = true;
var numberLiteral = 1;
var stringLiteral = 'true';

// Literal structures (type2)
var arrayLiteral = [];
var objectLiteral = {};

// Prototypes (type3)
var booleanPrototype = new Bool(true);
var numberPrototype = new Number(1);
var stringPrototype = new String('true');
var arrayPrototype = new Array();
var objectPrototype = new Object(); # or "new function () {}"

Da questi elementi possiamo creare tre tipi di array.

// 1) Array of literal-values (boolean, number, string) 
var type1 = [true, 1, "true"];

// 2) Array of literal-structures (array, object)
var type2 = [[], {}];

// 3) Array of prototype-objects (function)
var type3 = [function () {}, function () {}];

Le tecniche di copia profonda dipendono dai tre tipi di array

In base ai tipi di elementi nell'array, possiamo utilizzare varie tecniche per la copia profonda.

  • Matrice di valori letterali (tipo1)
    Le myArray.splice(0) , myArray.slice() e myArray.concat() possono essere utilizzate per copiare in profondità array con valori letterali (boolean, numero e stringa); dove Slice ha prestazioni più elevate di Concat ( http://jsperf.com/duplicate-array-slice-vs-concat/3 ).

  • Matrice di valori letterali (tipo1) e letterali (tipo2)
    La JSON.parse(JSON.stringify(myArray)) può essere utilizzata per copiare in profondità i valori letterali (boolean, numero, stringa) e le strutture letterali (array, oggetto), ma non gli oggetti prototipo.

  • Tutti gli array (tipo1, tipo2, tipo3)
    La tecnica jQuery $.extend(myArray) può essere utilizzata per copiare in profondità tutti i tipi di array. Le librerie come Underscore e Lo-dash offrono simili funzioni di deep-copy a jQuery $.extend() , ma hanno prestazioni inferiori. Più sorprendentemente, $.extend() ha prestazioni più elevate della JSON.parse(JSON.stringify(myArray)) http://jsperf.com/js-deep-copy/15 .
    E per quegli sviluppatori che evitano le librerie di terze parti (come jQuery), puoi usare la seguente funzione personalizzata; che ha prestazioni più elevate di $. Estendi e copia in profondità tutti gli array.

    function copy(o) {
      var output, v, key;
      output = Array.isArray(o) ? [] : {};
      for (key in o) {
        v = o[key];
        output[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
      }
      return output;
    }  
    

Quindi, per rispondere alla domanda ...

Domanda

var arr1 = ['a','b','c'];
var arr2 = arr1;

Ho capito che arr2 si riferisce allo stesso array di arr1, piuttosto che a un nuovo array indipendente. Come posso copiare l'array per ottenere due array indipendenti?

Risposta

Poiché arr1 è una matrice di valori letterali (booleana, numero o stringa), è possibile utilizzare qualsiasi tecnica di copia profonda discussa sopra, in cui slice ha le prestazioni più elevate.

// Highest performance for deep copying literal values
arr2 = arr1.slice();

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above

Nel mio caso particolare dovevo assicurarmi che la matrice rimanesse intatta, quindi questo ha funzionato per me:

// Empty array
arr1.length = 0;
// Add items from source array to target array
for (var i = 0; i < arr2.length; i++) {
    arr1.push(arr2[i]);
}

Per l'array ES6 contenente oggetti

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}

Personalmente ritengo che Array.from sia una soluzione più leggibile. A proposito, basta stare attenti al supporto del browser.

//clone
let x = [1,2,3];
let y = Array.from(x);

//deep clone
let clone = arr => Array.from(arr,item => Array.isArray(item) ? clone(item) : item);
let x = [1,[],[[]]];
let y = clone(x);

Quando vogliamo copiare un array usando l'operatore di assegnazione ( = ) non crea una copia, semplicemente copia il puntatore / riferimento alla matrice. Per esempio:

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

Spesso, quando trasformiamo i dati, vogliamo mantenere intatta la nostra infrastruttura dati iniziale (ad es. Array). Facciamo questo facendo una copia esatta del nostro array in modo che questo possa essere trasformato mentre quello iniziale rimane intatto.

Modi per copiare un array:

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

Fai attenzione quando gli array o gli oggetti sono nidificati !:

Quando gli array sono nidificati, i valori vengono copiati per riferimento. Ecco un esempio di come ciò potrebbe portare a problemi:

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

Quindi non usare questi metodi quando ci sono oggetti o array all'interno dell'array che si desidera copiare. cioè Utilizzare questi metodi solo su matrici di primitivi.

Se vuoi raddrizzare un array javascript, usa JSON.parse insieme a JSON.stringify , in questo modo:

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

Prestazioni di copia:

Quindi quale sceglieremo per prestazioni ottimali. Risulta che il metodo più dettagliato, il ciclo for ha le massime prestazioni. Usa il ciclo for per una copia veramente intensiva della CPU (array di grandi dimensioni / molti).

Successivamente, anche il metodo .slice() ha prestazioni decenti ed è anche meno dettagliato e più semplice da implementare per il programmatore. Suggerisco di usare .slice() per la copia quotidiana di array che non .slice() molta CPU. Evita anche di usare JSON.parse(JSON.stringify(arr)) (un sacco di spese generali) se non è richiesto alcun clone profondo e le prestazioni sono un problema.

Test delle prestazioni della sorgente


Questo è come l'ho fatto dopo aver provato molti approcci:

var newArray = JSON.parse(JSON.stringify(orgArray));

Ciò creerà una nuova copia profonda non correlata alla prima (non una copia superficiale).

Anche questo ovviamente non clonerà eventi e funzioni, ma la cosa buona è che puoi farlo in una riga, e può essere usato per qualsiasi tipo di oggetto (matrici, stringhe, numeri, oggetti ...)


Se si desidera creare una nuova copia di un oggetto o di un array, è necessario copiare esplicitamente le proprietà dell'oggetto o degli elementi dell'array, ad esempio:

var arr1 = ['a','b','c'];
var arr2 = [];

for (var i=0; i < arr1.length; i++) {
   arr2[i] = arr1[i];
}

Puoi cercare ulteriori informazioni su Google su valori primitivi immutabili e riferimenti a oggetti mutabili.



Usa questo:

var newArray = oldArray.slice();

Fondamentalmente, l'operazione slice() clona la matrice e restituisce un riferimento a una nuova matrice. Si noti inoltre che:

Per riferimenti, stringhe e numeri (e non l'oggetto reale), slice() copia i riferimenti oggetto nel nuovo array. Sia l'originale che il nuovo array si riferiscono allo stesso oggetto. Se un oggetto di riferimento cambia, le modifiche sono visibili sia per gli array nuovi che per quelli originali.

I primitivi come stringhe e numeri sono immutabili, quindi le modifiche alla stringa o al numero sono impossibili.


Usando jQuery copia profonda potrebbe essere fatta come segue:

var arr2 = $.extend(true, [], arr1);

Importante!

La maggior parte delle risposte qui funziona per casi particolari .

Se non ti interessa l'uso di oggetti e oggetti di scena nidificati / profondi ( ES6 ):

let clonedArray = [...array]

ma se vuoi fare un clone profondo, usa questo:

let cloneArray = JSON.parse(JSON.stringify(array))

Per gli utenti di lodash:

let clonedArray = _.clone(array) documentation

e

let clonedArray = _.cloneDeep(array)





arrays