Salin array dengan nilai

1745

Saat menyalin array dalam JavaScript ke array lain:

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

Saya menyadari bahwa arr2mengacu pada array yang sama dengan arr1, bukan array baru yang independen. Bagaimana saya bisa menyalin array untuk mendapatkan dua array independen?

Dan
sumber
3
Sepertinya saat ini di Chrome 53 dan Firefox 48 kami memiliki kinerja keren untuk slicedan spliceoperasi dan operator penyebaran baru dan Array.frommemiliki implementasi yang jauh lebih lambat. Lihatlah perfjs.fnfo
Pencroff
jsben.ch/#/wQ9RU <= patokan ini memberikan ikhtisar tentang berbagai cara untuk menyalin array
EscapeNetscape
Untuk array ini (salah satu yang berisi string primitif) Anda dapat menggunakan var arr2 = arr1.splice();untuk salinan yang mendalam, tetapi teknik ini tidak akan bekerja jika elemen dalam array mengandung struktur literal (yaitu []atau {}) atau benda prototipe (yaitu function () {}, new, dll). Lihat jawaban saya di bawah ini untuk solusi lebih lanjut.
tfmontague
16
Ini tahun 2017, jadi Anda dapat mempertimbangkan untuk menggunakan fitur ES6: let arr2 = [...arr1]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Hinrich

Jawaban:

2701

Gunakan ini:

var newArray = oldArray.slice();

Pada dasarnya, slice()operasi mengkloning array dan mengembalikan referensi ke array baru.

Perhatikan juga bahwa:

Untuk referensi, string, dan angka (dan bukan objek sebenarnya), slice()salin referensi objek ke dalam array baru. Baik array asli dan baru merujuk ke objek yang sama. Jika objek yang direferensikan berubah, perubahan tersebut dapat dilihat oleh array baru dan asli.

Primitif seperti string dan angka tidak dapat diubah, sehingga perubahan pada string atau angka tidak dimungkinkan.

Saket
sumber
9
Mengenai kinerja, tes jsPerf berikut ini benar-benar menunjukkan bahwa var arr2 = arr1.slice () sama cepatnya dengan var arr2 = arr1.concat (); JSPerf: jsperf.com/copy-array-slice-vs-concat/5 dan jsperf.com/copy-simple-array . Hasil dari jsperf.com/array-copy/5 agak mengejutkan saya sampai-sampai saya bertanya-tanya apakah kode tes itu valid.
Cohen
94
Meskipun ini telah menerima satu ton upvote, itu pantas mendapatkan yang lain karena ia dengan tepat menggambarkan referensi di JS, yang agak langka, sayangnya.
Wayne
34
@ GáborImre Anda akan menambahkan seluruh perpustakaan hanya untuk dibaca? Betulkah? Saya hanya akan menambahkan komentar jika saya peduli dengan keterbacaan. Lihat: var newArray = oldArray.slice (); // Klon oldArray ke newArray
dudewad
12
@ GáborImre saya mengerti, tentu saja. Tapi menjawab masalah teknik tertentu dengan memasukkan seluruh perpustakaan menurut saya tidak membantu, itu desain yang menggembung. Saya melihat banyak pengembang melakukan itu, dan kemudian Anda berakhir dengan proyek yang mencakup seluruh kerangka kerja untuk menggantikan harus menulis fungsi tunggal. Hanya MO saya.
dudewad
5
Hal yang dipelajari: Jangan bingung .slice()dengan .splice(), yang memberi Anda array kosong. Perbedaan besar.
crazypeter
531

Dalam Javascript, teknik salin dalam bergantung pada elemen dalam array. Ayo mulai dari sana.

Tiga jenis elemen

Elemen dapat berupa: nilai literal, struktur literal, 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 () {}];

Teknik penyalinan dalam tergantung pada tiga jenis array

Berdasarkan jenis elemen dalam array, kita dapat menggunakan berbagai teknik untuk menyalin dalam.

Teknik menyalin dalam Javascript berdasarkan jenis elemen

  • Array literal-nilai (type1)
    The [...myArray], myArray.splice(0), myArray.slice(), dan myArray.concat()teknik dapat digunakan untuk array salinan yang mendalam dengan nilai-nilai literal (boolean, nomor, dan string) saja; di mana operator Spread [...myArray]memiliki kinerja terbaik ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).

  • Array literal-nilai (type1) dan literal-struktur (type2)
    The JSON.parse(JSON.stringify(myArray))Teknik dapat digunakan untuk nilai-nilai copy dalam literal (boolean, nomor, string) dan struktur literal (array, objek), tetapi tidak prototipe benda.

  • Semua array (type1, type2, type3) Teknik
    jQuery $.extend(myArray)dapat digunakan untuk menyalin semua tipe array. Perpustakaan seperti Underscore dan Lo-dash menawarkan fungsi salin yang serupa ke jQuery $.extend() , namun memiliki kinerja yang lebih rendah. Lebih mengejutkan, $.extend()memiliki kinerja lebih tinggi daripada JSON.parse(JSON.stringify(myArray))teknik http://jsperf.com/js-deep-copy/15 .
    Dan untuk pengembang yang menghindar dari perpustakaan pihak ketiga (seperti jQuery), Anda dapat menggunakan fungsi kustom berikut; yang memiliki kinerja lebih tinggi dari $. memperpanjang, dan menyalin semua array.

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

Jadi untuk menjawab pertanyaan ...

Pertanyaan

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

Saya menyadari bahwa arr2 merujuk ke array yang sama dengan arr1, daripada array independen yang baru. Bagaimana saya bisa menyalin array untuk mendapatkan dua array independen?

Menjawab

Karena arr1merupakan array nilai literal (boolean, angka, atau string), Anda dapat menggunakan teknik penyalinan dalam apa pun yang dibahas di atas, di mana operator spread ...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
Timbul
sumber
1
Banyak dari pendekatan ini tidak bekerja dengan baik. Menggunakan operator penugasan berarti Anda harus menetapkan kembali nilai literal asli dari arr1. Sangat jarang hal itu terjadi. Menggunakan splicemelenyapkan arr1, jadi itu bukan salinan sama sekali. Menggunakan JSONakan gagal jika salah satu nilai dalam array adalah Functions atau memiliki prototipe (seperti a Date).
Dancrumb
Menggunakan sambungan adalah solusi parsial. Ini akan gagal dalam kasus yang jauh lebih banyak daripada JSON. Splice membuat salinan dalam dari string dan angka, ketika nilai bergerak - tidak pernah mengatakan itu mengembalikan salinan.
tfmontague
1
Mengapa splice (0)? Bukankah seharusnya slice ()? Saya pikir itu seharusnya tidak mengubah array asli, yang tidak splice. @JamesMontagne
helpse
2
sambatan akan membuat pointer ke elemen dalam array asli (salinan dangkal). splice (0) akan mengalokasikan memori baru (salinan dalam) untuk elemen dalam array yang berupa angka atau string, dan membuat pointer untuk semua jenis elemen lainnya (salinan dangkal). Dengan melewatkan nilai awal nol ke metode fungsi sambatan, itu tidak akan splice elemen dari array asli, dan karena itu tidak memodifikasinya.
tfmontague
1
Sebenarnya, hanya ada satu jenis array: sebuah array "sesuatu". Tidak ada perbedaan antara [0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]dan array lainnya.
wizzwizz4
189

Anda dapat menggunakan spread array ...untuk menyalin array.

const itemsCopy = [...items];

Juga jika ingin membuat array baru dengan yang sudah ada menjadi bagian darinya:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];

Spread array sekarang didukung di semua browser utama tetapi jika Anda membutuhkan dukungan yang lebih lama gunakan skrip atau babel dan kompilasi ke ES5.

Info lebih lanjut tentang spread

Luke Femur
sumber
1
Ini tidak akan berfungsi untuk salinan dalam. Klon Jauh dan Array dalam JavaScript .
SNag
151

Tidak perlu jQuery ... Contoh Kerja

var arr2 = arr1.slice()

Ini menyalin array dari posisi awal 0 hingga akhir array.

Penting untuk dicatat bahwa ini akan berfungsi seperti yang diharapkan untuk tipe primitif (string, angka, dll.), Dan juga untuk menjelaskan perilaku yang diharapkan untuk tipe referensi ...

Jika Anda memiliki larik tipe Referensi, katakanlah tipe Object. Array akan disalin, tetapi kedua array akan berisi referensi ke yang sama Object. Jadi dalam hal ini akan terlihat seperti array disalin oleh referensi meskipun array sebenarnya disalin.

jondavidjohn
sumber
12
Tidak, ini tidak akan menjadi salinan yang mendalam.
jondavidjohn
Coba ini; var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
pradeep1991singh
2
Apa perbedaan antara jawaban ini dan jawaban yang diterima?
Isaac Pak
mendapatkan kesalahan di konsol untuk contoh Anda yang diberikan "TypeError: window.addEvent bukan fungsi"
Ravi Sharma
72

Alternatif sliceadalah concat, yang dapat digunakan dalam 2 cara. Yang pertama mungkin lebih mudah dibaca karena perilaku yang dimaksud sangat jelas:

var array2 = [].concat(array1);

Metode kedua adalah:

var array2 = array1.concat();

Cohen (dalam komentar) menunjukkan bahwa metode yang terakhir ini memiliki kinerja yang lebih baik .

Cara kerjanya adalah bahwa concat metode ini menciptakan array baru yang terdiri dari elemen-elemen dalam objek yang dipanggil diikuti oleh elemen-elemen dari setiap array yang diteruskan kepadanya sebagai argumen. Jadi ketika tidak ada argumen yang dilewatkan, itu hanya menyalin array.

Lee Penkman, juga di komentar, menunjukkan bahwa jika ada kesempatan array1adalah undefined, Anda dapat mengembalikan array kosong sebagai berikut:

var array2 = [].concat(array1 || []);

Atau, untuk metode kedua:

var array2 = (array1 || []).concat();

Perhatikan bahwa Anda juga dapat melakukan ini dengan slice: var array2 = (array1 || []).slice();.

Ninjakannon
sumber
31
Sebenarnya Anda juga bisa melakukannya: var array2 = array1.concat (); Ini jauh lebih cepat mengenai kinerja. (JSPerf: jsperf.com/copy-simple-array dan jsperf.com/copy-array-slice-vs-concat/5
Cohen
5
Perlu dicatat bahwa jika array1 bukan sebuah array maka [].concat(array1)mengembalikan [array1]misalnya jika itu tidak ditentukan, Anda akan mendapatkan [undefined]. Saya kadang-kadang melakukannyavar array2 = [].concat(array1 || []);
lee penkman
60

Inilah yang saya lakukan setelah mencoba banyak pendekatan:

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

Ini akan membuat salinan dalam baru yang tidak terkait dengan yang pertama (bukan salinan dangkal).

Juga ini jelas tidak akan mengkloning acara dan fungsi, tetapi hal baiknya Anda dapat melakukannya dalam satu baris, dan itu dapat digunakan untuk segala jenis objek (array, string, angka, objek ...)

Chtiwi Malek
sumber
4
Ini yang terbaik. Saya menggunakan metode yang sama sejak lama dan berpikir bahwa tidak ada lagi pengertian di loop rekursif sekolah lama
Vladimir Kharlampidi
1
Ketahuilah bahwa opsi ini tidak menangani struktur seperti grafik: macet di hadapan siklus, dan tidak mempertahankan referensi yang dibagikan.
Ruben
1
Ini juga gagal untuk hal-hal seperti Date, atau memang, apa pun yang memiliki prototipe. Selain itu, undefineds dapat dikonversi ke nulls.
Dancrumb
7
Apakah tidak ada yang cukup berani untuk mengomentari inefisiensi kotor pada CPU dan memori serialisasi ke teks dan kemudian menguraikan kembali ke suatu objek?
Lawrence Dol
3
Solusi ini adalah satu-satunya yang berhasil. Menggunakan slice () benar-benar solusi palsu.
20

Beberapa metode yang disebutkan bekerja dengan baik ketika bekerja dengan tipe data sederhana seperti angka atau string, tetapi ketika array berisi objek lain metode ini gagal. Ketika kami mencoba untuk meneruskan objek apa pun dari satu array ke array lainnya, ia dilewatkan sebagai referensi, bukan objek.

Tambahkan kode berikut dalam file JavaScript Anda:

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 cukup gunakan

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

Itu akan berhasil.

sarvesh singh
sumber
2
saya mendapatkan kesalahan ini ketika saya menambahkan kode ini ke halaman saya 'Uncaught RangeError: Ukuran stack panggilan maksimum terlampaui'
sawe
1
Maaf, kesalahan ini terjadi di chrome jika arr1 tidak dideklarasikan. jadi saya salin-tempel kode di atas, dan saya mendapatkan kesalahan, namun, jika saya mendeklarasikan array arr1, maka saya tidak mendapatkan kesalahan. Anda dapat meningkatkan jawabannya dengan mendeklarasikan arr1 tepat di atas arr2, saya melihat ada beberapa 'kami' di luar sana yang tidak mengenali bahwa kami harus mendeklarasikan arr1 (sebagian karena ketika saya mengevaluasi jawaban Anda, saya sedang terburu-buru dan membutuhkan sesuatu yang 'hanya berfungsi')
sawe
.slice()masih berfungsi dengan baik bahkan jika Anda memiliki objek dalam array Anda: jsfiddle.net/edelman/k525g
Jason
7
@Jason tetapi objek masih menunjuk ke objek yang sama sehingga mengubah yang satu akan mengubah yang lain. jsfiddle.net/k525g/1
Samuel
Kode yang sangat baik. Satu pertanyaan yang saya miliki, saya benar-benar mencoba untuk menyalin satu array ke yang lain seperti ini var arr1 = new Array () dan kemudian var arr2 = arr1; Jika saya mengubah sesuatu di arr2, perubahan juga terjadi pada arr1. Namun, jika saya menggunakan prototipe klon yang Anda buat, itu sebenarnya membuat contoh baru lengkap dari array itu atau dengan kata lain menyalinnya. Jadi ini masalah browser? atau javascript secara default menetapkan dua variabel dengan satu menunjuk ke yang lain dengan menggunakan pointer ketika seseorang melakukan var arr2 = arr1 dan mengapa tidak terjadi dengan variabel integer? lihat jsfiddle.net/themhz/HbhtA
themhz
17

Dari ES2015,

var arr2 = [...arr1];
Boopathi Rajaa
sumber
17

Saya pribadi berpikir bahwa Array . Dari solusi yang lebih mudah dibaca. Omong-omong, berhati-hatilah dengan dukungan browsernya.

//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);
Lewis
sumber
1
Ya, ini sangat mudah dibaca. The .slice()solusi adalah benar-benar unintuitive. Terima kasih untuk ini.
Banago
15

Penting!

Sebagian besar jawaban di sini berfungsi untuk kasus-kasus tertentu .

Jika Anda tidak peduli tentang penggunaan benda dalam dan bersarang ( ES6 ):

let clonedArray = [...array]

tetapi jika Anda ingin melakukan klon yang dalam gunakan ini sebagai gantinya:

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


Untuk pengguna lodash:

let clonedArray = _.clone(array) dokumentasi

dan

let clonedArray = _.cloneDeep(array) dokumentasi

ulou
sumber
11

Jika Anda berada di lingkungan ECMAScript 6 , menggunakan Spread 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>

Walter Chapilliquen - wZVanG
sumber
9

Menambahkan ke solusi array.slice (); perlu diketahui bahwa jika Anda memiliki sub-array array multidimensi akan disalin oleh referensi. Apa yang dapat Anda lakukan adalah untuk loop dan mengiris () setiap 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 objek, mereka akan disalin dengan referensi, Anda harus menyalinnya secara manual

A.Zaben
sumber
Jawaban ini layak mendapat tempat di dekat bagian atas halaman! Saya sedang bekerja dengan sub array multidimensi dan tidak bisa mengikuti mengapa array dalam selalu disalin oleh ref dan bukan oleh val. Logika sederhana ini memecahkan masalah saya. Saya akan memberi Anda +100 jika memungkinkan!
Mac
8

Nilai-nilai primitif selalu dilewati oleh nilainya (disalin). Namun nilai gabungan dilewatkan dengan referensi.

Jadi bagaimana kita menyalin arr ini?

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

Salin Array di ES6

let arrCopy = [...arr]; 

Salin dan Array di ES5

let arrCopy = arr.slice(); 
let arrCopy = [].concat(arr);

Mengapa `biarkan arrCopy = arr` tidak melewati nilai?

Melewati satu variabel ke variabel lain pada nilai Compound seperti Object / Array berperilaku berbeda. Menggunakan operator asign pada nilai-nilai copand kami meneruskan referensi ke objek. Inilah sebabnya mengapa nilai kedua array berubah ketika menghapus / menambahkan elemen arr.

Pengecualian:

arrCopy[1] = 'adding new value this way will unreference';

Ketika Anda menetapkan nilai baru ke variabel, Anda mengubah referensi itu sendiri dan itu tidak mempengaruhi Objek / Array asli.

Baca lebih banyak

DevWL
sumber
6

Seperti yang kita ketahui dalam array dan objek Javascript adalah dengan referensi, tetapi cara apa yang bisa kita lakukan menyalin array tanpa mengubah array asli nanti?

Berikut ini beberapa cara untuk melakukannya:

Bayangkan kita memiliki larik ini dalam kode Anda:

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

1) Looping melalui array dalam suatu fungsi dan mengembalikan array baru, seperti ini:

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

2) Menggunakan metode slice, slice adalah untuk mengiris bagian dari array, itu akan mengiris beberapa bagian dari array Anda tanpa menyentuh aslinya, dalam slice, jika tidak menentukan awal dan akhir array, itu akan mengiris keseluruhan array dan pada dasarnya membuat salinan penuh array, sehingga kita dapat dengan mudah mengatakan:

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

3) Juga metode kontak, ini untuk menggabungkan dua array, tetapi kita bisa menentukan satu array dan kemudian ini pada dasarnya membuat salinan nilai-nilai dalam array yang dihubungi baru:

var arr2 = arr.concat();

4) Juga metode string dan parse, itu tidak disarankan, tetapi bisa menjadi cara mudah untuk menyalin Array dan Objek:

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

5) metode Array.from, ini tidak didukung secara luas, sebelum digunakan periksa dukungan di browser yang berbeda:

const arr2 = Array.from(arr);

6) Cara ECMA6, juga tidak sepenuhnya didukung, tetapi babelJs dapat membantu Anda jika Anda ingin melakukan transile:

const arr2 = [...arr];
Alireza
sumber
6
let a = [1,2,3];

Sekarang Anda dapat melakukan salah satu dari yang berikut ini untuk membuat salinan 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 adalah [1,2,3,5] tetapi b masih [1,2,3] karena memiliki referensi yang berbeda.

Tetapi saya pikir, dalam semua metode di atas Array.from lebih baik dan dibuat terutama untuk menyalin array.

Nitesh Ranjan
sumber
1
yang mana yang tercepat?
Marc Frame
5

Saya pribadi lebih suka dengan cara ini:

JSON.parse(JSON.stringify( originalObject ));
Diemauerdk
sumber
Jadi cara yang disarankan di sini ?
Script47
4

Dalam kasus khusus saya, saya perlu 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]);
}
Brent Keller
sumber
2
+1 untuk tidak menambahkan ketidakjelasan pada kode Anda dengan memanggil fungsi yang melakukan hal yang persis sama, tetapi dengan cara yang kurang jelas. slice mungkin lebih efisien di bawah tenda, tetapi bagi siapa pun yang mengerjakan kode, ini menunjukkan maksud Anda. ditambah itu membuatnya lebih mudah untuk mengoptimalkan nanti, jika Anda ingin (misalnya) menyaring apa yang Anda salin. Namun perhatikan ini tidak menangani penyalinan dalam, dan objek internal yang sama diteruskan ke array baru, dengan referensi. Ini mungkin yang ingin Anda lakukan, mungkin juga tidak.
tidak sinkron
4

Buat salinan array / objek multidimensi:

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

tinta
sumber
3

Dan, tidak perlu menggunakan trik mewah. Yang perlu Anda lakukan adalah membuat salinan arr1 dengan melakukan ini.

var arr2 = new Array(arr1);

Sekarang arr1dan arr2dua variabel array berbeda disimpan di tumpukan terpisah. Lihat ini di jsfiddle .

DragoRaptor
sumber
Ini tidak menyalin array. Itu menciptakan array dengan satu elemen yang mereferensikan yang asli (yaitu var arr2 = [arr1];).
Timothy003
3

Ketika kita ingin menyalin array menggunakan operator penugasan ( =) itu tidak membuat salinan itu hanya menyalin pointer / referensi ke array. Sebagai contoh:

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, kita ingin mempertahankan struktur data awal kita (misalnya Array). Kami melakukan ini dengan membuat salinan yang tepat dari array kami sehingga yang ini dapat diubah sementara yang awal tetap utuh.

Cara menyalin 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);

Hati-hati saat array atau objek bersarang !:

Ketika array bersarang nilai disalin oleh referensi. Berikut adalah contoh bagaimana hal ini dapat 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 jangan gunakan metode ini ketika ada objek atau array di dalam array yang ingin Anda salin. yaitu Gunakan metode ini hanya pada array primitif.

Jika Anda ingin mendalami penggunaan array javascript JSON.parsebersama 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

Kinerja penyalinan:

Jadi yang mana yang kita pilih untuk kinerja yang optimal. Ternyata metode yang paling verbose, forloop memiliki kinerja tertinggi. Gunakan forloop untuk menyalin intensif CPU (array besar / banyak).

Setelah itu .slice()metode ini juga memiliki kinerja yang layak dan juga kurang bertele-tele dan lebih mudah bagi programmer untuk diimplementasikan. Saya sarankan untuk digunakan .slice()untuk menyalin array Anda sehari-hari yang tidak terlalu intensif CPU. Juga hindari menggunakanJSON.parse(JSON.stringify(arr)) (banyak overhead) jika tidak diperlukan klon dalam dan kinerja adalah masalah.

Uji kinerja sumber

Willem van der Veen
sumber
3

Jika array Anda mengandung elemen tipe data primitif seperti int, char, atau string dll, maka Anda dapat menggunakan salah satu metode yang mengembalikan salinan array asli seperti .slice () atau .map () atau operator spread ( terima kasih kepada ES6).

new_array = old_array.slice()

atau

new_array = old_array.map((elem) => elem)

atau

const new_array = new Array(...old_array);

TETAPI jika array Anda mengandung elemen kompleks seperti objek (atau array) atau lebih banyak objek bersarang , maka, Anda harus memastikan bahwa Anda membuat salinan semua elemen dari tingkat atas ke tingkat terakhir selain referensi bagian dalam objek akan digunakan dan itu berarti mengubah nilai dalam object_elements di new_array masih akan mempengaruhi old_array. Anda dapat memanggil metode penyalinan ini di setiap level sebagai membuat COPY DALAM dari old_array.

Untuk penyalinan dalam, Anda dapat menggunakan metode yang disebutkan di atas untuk tipe data primitif di setiap tingkat tergantung pada jenis data atau Anda dapat menggunakan metode mahal ini (disebutkan di bawah) untuk membuat salinan dalam 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. Saya hanya telah disebutkan beberapa dari mereka untuk memberikan gambaran umum tentang apa yang terjadi ketika kita mencoba untuk menyalin array ke yang lain dengan nilai .

abhinav1602
sumber
Terima kasih banyak, jawaban Anda adalah satu-satunya yang bekerja untuk skenario saya,
albert sh
2

Jika Anda ingin membuat salinan baru dari suatu objek atau array, Anda harus secara eksplisit menyalin properti objek atau elemen-elemen array, misalnya:

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

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

Anda dapat mencari informasi lebih lanjut di Google tentang nilai-nilai primitif yang tidak berubah dan referensi objek yang bisa berubah.

Sotiris
sumber
1
Anda tidak perlu menyalin properti objek array secara eksplisit. Lihat jawaban Chtiwi Malek.
Magne
2

Menggunakan jQuery deep copy dapat dilakukan sebagai berikut:

var arr2 = $.extend(true, [], arr1);
Oleksandr Tsurika
sumber
2

Anda juga dapat menggunakan operator penyebaran ES6 untuk menyalin Array

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

Berikut beberapa cara untuk menyalin:

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 );

Ganesh Phirke
sumber
2

Anda dapat menggunakan ES6 dengan menyebarkan Opeartor, yang lebih sederhana.

arr2 = [...arr1];

Ada batasan..hapus dokumentasi. Sebarkan sintaks @ mozilla

BluePie
sumber
2

Contoh Cepat:

  1. Jika elemen dalam array adalah tipe primitif (string, angka, dll.)

var arr1 = ['a','b','c'];
// arr1 and arr2 are independent and primitive elements are stored in 
// different places in the memory
var arr2 = arr1.slice(); 
arr2.push('d');
console.log(arr1); // [ 'a', 'b', 'c' ]
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]

  1. Jika elemen dalam array adalah literal objek, array lain ({}, [])

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
// arr1 and arr2 are independent and reference's/addresses are stored in different
// places in the memory. But those reference's/addresses points to some common place
// in the memory.
var arr2 = arr1.slice(); 
arr2.pop();      // OK - don't affect arr1 bcos only the address in the arr2 is
                 // deleted not the data pointed by that address
arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area 
                 // pointed by the addresses in both arr1 and arr2
arr2[1][0] = 9;	 // not OK - same above reason

console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]

  1. Solusi untuk 2 : Salin Jauh oleh elemen demi elemen

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
arr2 = JSON.parse(JSON.stringify(arr1));
arr2.pop();	  // OK - don't affect arr1
arr2[0].x = 'z';  // OK - don't affect arr1
arr2[1][0] = 9;	  // OK - don't affect arr1

console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]

SridharKritha
sumber
1

Berikut variannya:

var arr1=['a', 'b', 'c'];
var arr2=eval(arr1.toSource());
arr2.push('d');
console.log('arr1: '+arr1+'\narr2: '+arr2);
/*
 *  arr1: a,b,c
 *  arr2: a,b,c,d
 */
Zyox
sumber
bukan ide yang buruk, meskipun saya lebih baik menggunakan JSON stringify / parse daripada eval, dan membandingkan jsPerf lain akan lebih baik untuk memeriksa, juga catatan toSourcetidak standar dan tidak akan berfungsi di Chrome misalnya.
dmi3y
1

Ada yang baru diperkenalkan Array.from, tetapi sayangnya, pada saat penulisan ini hanya didukung pada versi Firefox terbaru (32 dan lebih tinggi). Ini dapat dengan mudah digunakan sebagai berikut:

var arr1 = [1, 2, 3];
console.log(Array.from(arr1)); // Logs: [1, 2, 3]

Referensi: Di Sini

Atau Array.prototype.map dapat digunakan dengan fungsi identitas:

function identity(param)
{
    return param;
}

var arr1 = [1, 2, 3],
    clone = arr1.map(identity);

Referensi: Di Sini

Ashraf Sabry
sumber
+1 untuk disebutkan Array.from, yang sekarang didukung di semua browser utama kecuali Internet Explorer ( sumber ). .
mgthomas99
Waspadai Array.fromakan bermutasi data, tidak menyediakan penyalinan dalam / kloning dalam.
Sudhansu Choudhary
1

Untuk array ES6 yang berisi objek

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