Ketika menyalin sebuah array di JavaScript ke array lain:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
Saya menyadari bahwa arr2
mengacu pada array yang sama sebagai arr1
, bukan yang baru, independen array. Bagaimana saya bisa copy array untuk mendapatkan dua independen array?
Gunakan ini:
var newArray = oldArray.slice();
Pada dasarnya, slice()
operasi klon array dan mengembalikan referensi ke array baru.
Untuk referensi, string dan angka (dan bukan objek yang sebenarnya), slice()
salinan objek referensi ke array baru. Asli dan array baru yang mengacu pada objek yang sama. Jika objek direferensikan perubahan, perubahan yang terlihat untuk kedua baru dan asli array.
Primitif seperti string dan angka yang tidak berubah, sehingga perubahan pada string atau angka yang mustahil.
Dalam Javascript, deep-copy teknik yang tergantung pada elemen-elemen dalam array. Let's mulai dari sana.
Elemen dapat berupa: nilai literal, literal struktur, atau prototipe.
// Literal values (type1)
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';
// Literal structures (type2)
const arrayLiteral = [];
const objectLiteral = {};
// Prototypes (type3)
const booleanPrototype = new Bool(true);
const numberPrototype = new Number(1);
const stringPrototype = new String('true');
const arrayPrototype = new Array();
const objectPrototype = new Object(); # or "new function () {}"
Dari elemen-elemen ini kita dapat membuat tiga jenis array.
// 1) Array of literal-values (boolean, number, string)
const type1 = [true, 1, "true"];
// 2) Array of literal-structures (array, object)
const type2 = [[], {}];
// 3) Array of prototype-objects (function)
const type3 = [function () {}, function () {}];
Berdasarkan jenis elemen dalam array, kita dapat menggunakan berbagai teknik untuk deep copy.
Hotel yang literal-nilai (tipe1)
The [...myArray]
, myArray.sambatan(0)
, myArray.slice()
, dan myArray.concat()
teknik-teknik yang dapat digunakan untuk deep copy array dengan nilai literal (boolean, jumlah, dan string) saja; di mana Penyebaran operator [...myArray]
memiliki kinerja terbaik (https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat).
Hotel yang literal-nilai (tipe1) dan literal-struktur (tipe 2)
The JSON.mengurai(JSON.stringify(myArray))
teknik dapat digunakan untuk deep copy nilai literal (boolean, nomor, string) dan literal struktur (array, object), tapi tidak prototipe benda-benda.
Semua array (tipe1, tipe 2, type3)
JQuery $.memperpanjang(myArray)
teknik dapat digunakan untuk deep-copy semua array-jenis. Perpustakaan, seperti Underscore dan Lo-dash penawaran mirip deep-copy fungsi untuk jQuery $.memperpanjang()
, namun memiliki kinerja yang lebih rendah. Lebih mengejutkan, $.memperpanjang()
memiliki kinerja yang lebih tinggi daripada JSON.mengurai(JSON.stringify(myArray))
teknik http://jsperf.com/js-deep-copy/15.
Dan untuk para pengembang yang menghindar dari pustaka pihak ketiga (seperti jQuery), anda dapat menggunakan fungsi kustom berikut; yang memiliki kinerja yang lebih tinggi dari $.memperpanjang, dan dalam salinan semua array.
fungsi copy(aObject) {
jika (!aObject) {
kembali aObject;
}
biarkan v;
mari bObject = Array.isArray(aObject) ? [] : {};
untuk (const k di aObject) {
v = aObject[k];
bObject[k] = (typeof v === "objek") ? copy(v) : v;
}
kembali bObject;
}
Pertanyaan
var arr1 = ['a','b','c'];
var arr2 = arr1;
saya menyadari bahwa arr2 mengacu pada array yang sama sebagai arr1, daripada baru, independen array. Bagaimana saya bisa copy array untuk mendapatkan dua independen array?
Jawaban
Karena arr1
adalah array dari nilai literal (boolean, nomor, atau string), anda dapat menggunakan salah dalam menyalin teknik yang dibahas di atas, di mana penyebaran operator ...
memiliki kinerja tertinggi.
// Highest performance for deep copying literal values
arr2 = [...arr1];
// Any of these techniques will deep copy literal values as well,
// but with lower performance.
arr2 = arr1.slice();
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
Anda dapat menggunakan array menyebar ...
untuk menyalin array.
const itemsCopy = [...item];
Juga jika ingin membuat array baru dengan yang sudah ada menjadi bagian dari itu:
var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
Hotel yang menyebar sekarang didukung di semua browser utama tetapi jika anda membutuhkan dukungan yang lebih tua menggunakan naskah atau babel dan mengkompilasi untuk ES5.
Tidak ada jQuery yang dibutuhkan... [Contoh Kerja][1]
var arr2 = arr1.slice()
Ini copys array dari posisi awal 0
sampai akhir array.
Hal ini penting untuk dicatat bahwa itu akan bekerja seperti yang diharapkan untuk tipe primitif (string, jumlah, dll.), dan juga menjelaskan perilaku yang diharapkan untuk referensi jenis...
Jika anda memiliki sebuah array dari jenis Referensi, mengatakan dari jenis Objek
. Array *akan * disalin, tetapi kedua dari array akan berisi referensi yang sama Objek
's. Jadi dalam hal ini tampaknya seperti array disalin oleh referensi meskipun array adalah benar-benar disalin.**
Alternatif untuk iris
adalah concat
, yang dapat digunakan dalam 2 cara. Yang pertama ini mungkin lebih mudah dibaca seperti yang dimaksudkan adalah perilaku yang sangat jelas:
var array2 = [].concat(array1);
Metode kedua adalah:
var array2 = array1.concat();
Cohen (dalam komentar) menunjukkan bahwa kedua metode memiliki kinerja yang lebih baik.
Cara ini bekerja adalah bahwa concat
metode menciptakan sebuah array baru yang terdiri dari elemen-elemen dalam obyek yang disebut diikuti oleh unsur-unsur dari setiap array yang dilewatkan sebagai argumen. Jadi, ketika tidak ada argumen yang berlalu, itu hanya salinan array.
Lee Penkman, juga di komentar, menunjukkan bahwa jika ada's kesempatan array1
adalah undefined
, anda dapat mengembalikan array kosong sebagai berikut:
var array2 = [].concat(array1 || []);
Atau, untuk metode kedua:
var array2 = (array1 || []).concat();
Catatan bahwa anda juga dapat melakukan ini dengan iris
: var array2 = (array1 || []).slice();
.
Ini adalah bagaimana saya've dilakukan setelah mencoba beberapa pendekatan:
var newArray = JSON.parse(JSON.stringify(orgArray));
Ini akan membuat yang baru dalam salinan tidak terkait dengan yang pertama (tidak dangkal copy).
Ini juga jelas tidak akan clone peristiwa dan fungsi, tapi hal yang baik anda dapat melakukannya dalam satu baris, dan dapat digunakan untuk setiap jenis objek (array, string, angka, benda-benda ...)
Beberapa yang disebutkan metode bekerja dengan baik ketika bekerja dengan tipe data sederhana seperti angka atau string, tapi ketika array yang berisi benda-benda lain metode ini gagal. Ketika kita mencoba untuk melewati setiap objek dari satu array ke yang lain dilewatkan sebagai referensi, bukan obyek.
Tambahkan kode berikut di 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;
};
Dan hanya menggunakan
var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()
Ia akan bekerja.
Saya pribadi berpikir Array.from adalah lebih mudah dibaca solusi. By the way, hanya berhati-hati untuk dukungan 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);
Penting!
Sebagian besar dari jawaban di sini bekerja untuk kasus-kasus tertentu.
Jika anda don't peduli tentang deep/bersarang benda-benda dan alat peraga yang digunakan (ES6):
biarkan clonedArray = [...array]
tapi jika anda ingin melakukan deep clone gunakan ini sebagai gantinya:
biarkan cloneArray = JSON.mengurai(JSON.stringify(array))
Untuk lodash pengguna:
biarkan clonedArray = _.clone(array)
dokumentasi
dan
biarkan clonedArray = _.cloneDeep(array)
dokumentasi
Jika anda berada di lingkungan ECMAScript 6, dengan menggunakan Menyebar Operator anda bisa melakukannya dengan cara ini:
var arr1 = ['a','b','c'];
var arr2 = [...arr1]; //copy arr1
arr2.push('d');
console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>
Menambahkan larutan array.slice(); sadarilah bahwa jika anda memiliki array multidimensi sub-array akan disalin dengan referensi. Apa yang dapat anda lakukan adalah untuk loop dan slice() masing-masing sub-array secara individual
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]);
hal yang sama berlaku untuk array dari objek, mereka akan disalin dengan referensi, anda harus menyalinnya secara manual
Seperti yang kita tahu dalam Javascript array dan benda ini adalah sebagai referensi, tapi cara-cara apa yang bisa kita lakukan copy array tanpa mengubah array asli kemudian satu?
Berikut ini adalah beberapa cara untuk melakukannya:
Bayangkan kita memiliki array dalam kode anda:
var arr = [1, 2, 3, 4, 5];
function newArr(arr) {
var i=0, res = [];
while(i<arr.length){
res.push(arr[i]);
i++;
}
return res;
}
var arr2 = arr.slice(); // make a copy of the original array
var arr2 = arr.concat();
var arr2 = JSON.parse(JSON.stringify(arr));
const arr2 = Array.from(arr);
const arr2 = [...arr];
Membuat copy dari array multidimensi/objek:
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;
}
Terima kasih kepada James Padolsey untuk fungsi ini.
Sumber: Di Sini
let a = [1,2,3];
Sekarang anda dapat melakukan salah satu dari berikut ini untuk membuat salinan dari sebuah array.
let b = Array.from(a);
ATAU
let b = [...a];
ATAU
let b = new Array(...a);
ATAU
let b = a.slice();
ATAU
let b = a.map(e => e);
Sekarang, jika saya mengubah,
a.push(5);
Kemudian, a [1,2,3,5] tapi b masih [1,2,3] karena memiliki referensi yang berbeda.
Tapi saya pikir, dalam semua metode-metode di atas Array.dari adalah yang lebih baik dan dibuat terutama untuk menyalin sebuah array.
Dalam kasus tertentu yang saya butuhkan untuk memastikan array tetap utuh sehingga ini bekerja untuk saya:
// 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]);
}
Dan, tidak perlu menggunakan trik mewah. Semua yang perlu anda lakukan adalah membuat copy dari arr1 dengan melakukan hal ini.
var arr2 = new Array(arr1);
Sekarang arr1
dan arr2
adalah dua hal yang berbeda array variabel-variabel yang tersimpan di tumpukan terpisah.
[Lihat ini di jsfiddle][1].
Ketika kita ingin menyalin sebuah array menggunakan operator penugasan ( =
) itu doesn't membuat copy hanya salinan pointer/referensi ke array. Misalnya:
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
Seringkali ketika kita mengubah data kami ingin menjaga awal kami datastructure (misalnya Array) yang utuh. Kami melakukan ini dengan membuat salinan dari array kita jadi yang satu ini dapat berubah sementara yang awal tetap utuh.
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);
Ketika array yang bersarang nilai-nilai yang disalin oleh referensi. Berikut adalah contoh bagaimana ini bisa menyebabkan masalah:
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
Jadi don't menggunakan metode ini ketika ada benda-benda atau array dalam array yang ingin anda salin. yaitu Menggunakan metode ini pada array dari primitif saja.
Jika anda ingin deepclone javascript array menggunakan JSON.mengurai
dalam hubungannya dengan JSON.stringify
, seperti ini:
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
Jadi yang mana yang kita pilih untuk kinerja yang optimal. Ternyata yang paling verbose metode, untuk
loop memiliki kinerja tertinggi. Gunakan untuk
loop untuk benar-benar CPU intensif menyalin (besar/banyak array).
Setelah itu .slice()
metode ini juga memiliki kinerja yang layak dan juga kurang verbose dan lebih mudah bagi programmer untuk melaksanakan. Saya sarankan untuk menggunakan .slice()
untuk sehari-hari anda menyalin dari array yang tidak't sangat CPU intensif. Juga hindari menggunakan JSON.mengurai(JSON.stringify(arr))
(banyak overhead) jika tidak mendalam clone diperlukan dan kinerja adalah masalah.
Jika array berisi unsur-unsur primitif tipe data seperti int, char atau string dll maka anda bisa pengguna salah satu dari metode-metode yang mengembalikan salinan asli array seperti .slice() atau .peta() atau menyebar operator(terima kasih untuk ES6).
new_array = old_array.slice()
atau
new_array = old_array.map((elem) => elem)
atau
const new_array = new Array(...old_array);
TAPI jika array berisi unsur-unsur yang kompleks seperti benda-benda(atau array) atau lebih bersarang benda, kemudian, anda akan memiliki untuk memastikan bahwa anda membuat salinan dari semua elemen dari tingkat atas ke tingkat terakhir lagi referensi dari bagian dalam benda-benda yang akan digunakan dan itu berarti mengubah nilai-nilai dalam object_elements di new_array masih akan mempengaruhi old_array. Anda dapat memanggil metode ini menyalin pada setiap tingkat seperti membuat DALAM SALINAN dari old_array.
Untuk deep menyalin, anda dapat menggunakan yang disebutkan di atas metode primitif tipe data pada setiap tingkat tergantung pada jenis data atau anda dapat menggunakan ini metode mahal(yang disebutkan di bawah ini) untuk membuat dalam salinan tanpa melakukan banyak pekerjaan.
var new_array = JSON.parse(JSON.stringify(old_array));
Ada banyak metode lain di luar sana yang dapat anda gunakan tergantung pada kebutuhan anda. Yang telah saya sebutkan hanya beberapa orang untuk memberikan gambaran umum tentang apa yang terjadi ketika kita mencoba untuk menyalin sebuah array ke yang lain dengan nilai.