Bagaimana Anda mengkloning Array Objek di Javascript?

421

... di mana setiap objek juga memiliki referensi ke objek lain dalam array yang sama?

Ketika saya pertama kali datang dengan masalah ini saya hanya memikirkan sesuatu seperti

var clonedNodesArray = nodesArray.clone()

akan ada dan mencari info tentang cara mengkloning objek dalam javascript. Saya memang menemukan pertanyaan tentang StackOverflow (dijawab oleh @JohnResig yang sama) dan dia menunjukkan bahwa dengan jQuery Anda bisa melakukannya

var clonedNodesArray = jQuery.extend({}, nodesArray);

untuk mengkloning suatu objek. Saya mencoba ini, ini hanya menyalin referensi objek dalam array. Jadi kalau saya

nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"

nilai dari kedua nodesArray [0] dan cloningNodesArray [0] akan berubah menjadi "hijau". Lalu saya mencoba

var clonedNodesArray = jQuery.extend(true, {}, nodesArray);

yang dalam menyalin Obyek, tetapi saya mendapat " terlalu banyak rekursi " dan " control stack overflow " pesan dari Firebug dan Opera Dragonfly.

Bagaimana Anda melakukannya? Apakah ini sesuatu yang seharusnya tidak dilakukan? Apakah ada cara yang dapat digunakan kembali untuk melakukan ini dalam Javascript?

wallyqs
sumber

Jawaban:

106

Masalah dengan salinan dangkal Anda adalah bahwa semua objek tidak dikloning. Meskipun referensi untuk setiap objek unik di setiap array, setelah Anda akhirnya mengambilnya, Anda berurusan dengan objek yang sama seperti sebelumnya. Tidak ada yang salah dengan cara Anda mengkloningnya ... hasil yang sama akan terjadi menggunakan Array.slice ().

Alasan salinan Anda yang dalam mengalami masalah adalah karena Anda berakhir dengan referensi objek lingkaran. Deep akan sedalam itu bisa, dan jika Anda memiliki lingkaran, itu akan terus berlanjut hingga browser pingsan.

Jika struktur data tidak dapat direpresentasikan sebagai grafik asiklik terarah, maka saya tidak yakin Anda akan dapat menemukan metode serba guna untuk kloning dalam. Grafik siklik menyediakan banyak kasing sudut yang rumit, dan karena ini bukan operasi umum, saya ragu ada yang menulis solusi lengkap (jika itu mungkin - mungkin tidak! Tapi saya tidak punya waktu untuk mencoba menulis bukti yang kuat sekarang.). Saya menemukan beberapa komentar bagus tentang masalah di halaman ini .

Jika Anda memerlukan salinan mendalam dari Array Objek dengan referensi melingkar, saya yakin Anda harus memberi kode metode Anda sendiri untuk menangani struktur data khusus Anda, sehingga itu adalah kloning multi-pass:

  1. Di babak pertama, buat klon dari semua objek yang tidak mereferensikan objek lain dalam array. Catat asal usul setiap objek.
  2. Pada ronde kedua, hubungkan benda-benda itu menjadi satu.
Dan Lew
sumber
1
Tautan tetap untuk @PatrickdeKleijn jawaban: web.archive.org/web/20140222022056/http://my.opera.com/…
Mike Szyndel
531

Selama objek Anda mengandung konten JSON-serializable (tidak ada fungsi, tidak Number.POSITIVE_INFINITY, dll.) Tidak perlu ada loop untuk mengkloning array atau objek. Berikut ini adalah solusi satu garis vanila murni.

var clonedArray = JSON.parse(JSON.stringify(nodesArray))

Untuk meringkas komentar di bawah ini, keuntungan utama dari pendekatan ini adalah bahwa ia juga mengkloning isi array, bukan hanya array itu sendiri. Kelemahan utama adalah batasnya hanya bekerja pada konten JSON-serializable, dan kinerjanya (yang secara signifikan lebih buruk daripada slicependekatan berbasis).

Vladimir Kharlampidi
sumber
118
Ini mungkin bekerja untuk data JSON, tetapi jika array Anda berisi fungsi atau instance objek yang memiliki metode, ucapkan selamat tinggal kepada mereka.
sp0rkyd0rky
12
hati-hati jika Anda memiliki array yang berisi nilai Infinity. Nilai ini hilang (nol setelah itu). ( jsfiddle.net/klickagent/ehm4bd3s )
klickagent.ch
13
Ini umumnya hanya pendekatan yang buruk kecuali array Anda hanya berisi primitif, dan / atau objek yang hanya berisi string / angka / boolean primitif (genap nulldan undefinedakan menjadi masalah, karena JSON tidak mendukungnya). Lebih jauh, ini adalah operasi yang jauh lebih efisien daripada old_array.slice(0);, yang seharusnya bekerja lebih baik dan lebih cepat.
XML
2
jika objek array memiliki DateTime, maka string akan dikembalikan sebagai ganti DateTime! Tanggal baru! == JSON.parse (JSON.stringify (Tanggal baru))
MarkosyanArtur
2
Baris kunci dalam pertanyaan OP, yang diabaikan jawaban di atas sepenuhnya: ... di mana setiap objek juga memiliki referensi ke objek lain dalam array yang sama?
XML
288

Saya memecahkan kloning array objek dengan Object.assign

const newArray = myArray.map(a => Object.assign({}, a));

atau bahkan lebih pendek dengan sintaksis spread

const newArray = myArray.map(a => ({...a}));
dinodsaurus
sumber
15
Tetapi jika myArray berisi banyak Dinosaurus, newArray berisi banyak Obyek. Itu payah, tidakkah Anda setuju?
Matthew James Davis
3
pendekatan terbaik, karena menjaga fungsi objek tetap hidup, kemudian kehilangan mereka dengan JSON.parse (JSON.stringify (nodesArray))
scipper
14
@MatthewJamesDavis Anda dapat menyelesaikan ini dengan menggantinya {}dengan new Dinosaur().
Agargara
5
salinan dangkal tidak dalam salinan
sultan aslam
1
Ini berfungsi baik untuk array objek, jika objek-objek itu hanya mengandung properti primitif ... itulah yang saya butuhkan, terima kasih
mojave
154

Jika yang Anda butuhkan hanyalah salinan dangkal, cara yang sangat mudah adalah:

new_array = old_array.slice(0);
Leopd
sumber
6
Saya rasa Anda tidak harus lulus 0, Anda bisa menelepon .slice()setidaknya di chrome
slf
112
Ini sebenarnya tidak bekerja, bukan? Maksud saya, itu bukan jawaban untuk pertanyaan bagaimana mengkloning berbagai objek. Ini adalah solusi untuk mengkloning array sederhana.
bozdoz
35
Sebenarnya ini tidak akan berfungsi untuk array objek. Array yang dikembalikan oleh sliceakan menjadi array baru tetapi akan berisi referensi ke objek array asli.
Sergio A.
4
Ini hanya akan berfungsi untuk int "generik", string dll. Tetapi tidak untuk array objek.
Stefan Michev
5
untuk array objek yang sebenarnya tidak dikloning ini, pembaruan ke new_array juga akan memperbarui old_array.
Anas
44

Cara terbaik dan terbaru untuk melakukan klon ini adalah sebagai berikut:

Menggunakan ...operator penyebaran ES6.

Inilah Contoh yang paling sederhana:

var clonedObjArray = [...oldObjArray];

Dengan cara ini kami menyebarkan array ke nilai individual dan meletakkannya di array baru dengan operator [].

Berikut ini contoh yang lebih panjang yang menunjukkan berbagai cara kerjanya:

let objArray = [ {a:1} , {b:2} ];

let refArray = objArray; // this will just point to the objArray
let clonedArray = [...objArray]; // will clone the array

console.log( "before:" );
console.log( "obj array" , objArray );
console.log( "ref array" , refArray );
console.log( "cloned array" , clonedArray );

objArray[0] = {c:3};

console.log( "after:" );
console.log( "obj array" , objArray ); // [ {c:3} , {b:2} ]
console.log( "ref array" , refArray ); // [ {c:3} , {b:2} ]
console.log( "cloned array" , clonedArray ); // [ {a:1} , {b:2} ]

MennyMez
sumber
2
Jawaban modern yang bagus, itu tidak akan berfungsi dengan browser lama (seperti IE 11)
Jealie
1
@Jealie Saya akan menebak KingpinEX menargetkan jawaban ini untuk orang-orang yang mentransformasikan es6 ke sesuatu yang lebih bermanfaat secara universal dengan Babel atau apa pun yang Anda miliki.
ruffin
61
Ini hanya menyalin array, bukan setiap objek dalam array.
Toivo Säwén
31
Untuk menindaklanjuti apa yang dikatakan @ ToivoSäwén, ini tidak akan menyalin objek dalam array secara mendalam. Ini masih akan mereferensikan objek asli jadi jika Anda memutasikannya, itu akan berdampak pada array asli juga.
Joel Kinzel
3
Ini hanya berfungsi untuk primitif. Coba ini: objArray [0] .a = 3; dan Anda akan melihat referensi objek tetap sama di cloningArray.
Sergio Correa
25

Ini bekerja untuk saya:

var clonedArray = $.map(originalArray, function (obj) {
                      return $.extend({}, obj);
                  });

Dan jika Anda membutuhkan salinan objek dalam array:

var clonedArray = $.map(originalArray, function (obj) {
                      return $.extend(true, {}, obj);
                  });
vilik
sumber
1
Sepertinya ini akan berhasil. Saya mencoba untuk menghindari penggunaan jQuery yang luas, jadi saya tidak akan menggunakannya dalam situasi saya, tetapi for for loop dan for ... in akan berfungsi.
bozdoz
19
$.evalJSON($.toJSON(origArray));
elsereturn
sumber
2
Anda harus menggunakan plugin jquery json untuk menggunakan code.google.com/p/jquery-json
wmitchell
32
Tanpa JQ (baik di peramban modern):JSON.parse(JSON.stringify(origArray));
forresto
Saya menemukan komentar ini bermanfaat. Dalam implementasi saya, saya perlu membuat salinan dari array objek yang memiliki properti yang dapat diobservasi KnockoutJS diterapkan. Salinan hanya membutuhkan nilai-nilai, bukan nilai yang bisa diamati. Untuk membuat salinan JUST nilai yang saya gunakan JSON.parse (ko.toJSON (origArray)) ATAU ko.utils.parseJson (ko.toJSON (origArray)). Hanya 2 sen saya dan terima kasih telah membantu saya sampai pada solusi saya.
wavedrop
6
JSON.parse(JSON.stringify(origArray));jelas merupakan solusi paling sederhana.
yorkw
jQuery seringkali tidak perlu. youmightnotneedjquery.com
ADJenks
9

Peta akan membuat array baru dari yang lama (tanpa referensi ke yang lama) dan di dalam peta Anda membuat objek baru dan beralih ke properti (kunci) dan menetapkan nilai dari objek Array lama ke properti yang sesuai dengan objek baru.

Ini akan membuat array objek yang persis sama.

let newArray = oldArray.map(a => {
               let newObject = {};
               Object.keys(a).forEach(propertyKey => {
                    newObject[propertyKey] = a[propertyKey];
               });
               return newObject ;
});
eomeroff
sumber
8

Saya mungkin memiliki cara sederhana untuk melakukan ini tanpa harus melakukan rekursi yang menyakitkan dan tidak mengetahui semua detail objek yang dipertanyakan. Menggunakan jQuery, cukup konversikan objek Anda menjadi JSON menggunakan jQuery $.toJSON(myObjectArray), lalu ambil string JSON Anda dan evaluasi kembali ke suatu objek. BAM! Selesai, dan selesai! Masalah terpecahkan. :)

var oldObjArray = [{ Something: 'blah', Cool: true }];
var newObjArray = eval($.toJSON(oldObjArray));
George
sumber
21
Beberapa browser modern memiliki metode JSON built-in sehingga Anda dapat melakukan ini: JSON.parse (JSON.stringify (MY_ARRAY)) yang seharusnya lebih cepat. Saran yang bagus
Nicolas R
1
Dan jika mereka tidak menggunakan json2 , tidak eval.
kamranicus
Ini memiliki kinerja yang mengerikan, tetapi sayangnya adalah jawaban terbaik yang pernah saya lihat: /
Dvid Silva
Jangan evaluasi apa pun dengan data pengguna. Lebih disukai tidak pernah menggunakan eval()sama sekali. Ini risiko keamanan.
ADJenks
8

Saya menjawab pertanyaan ini karena sepertinya tidak ada solusi yang sederhana dan eksplisit untuk masalah "kloning array objek dalam Javascript":

function deepCopy (arr) {
    var out = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        var item = arr[i];
        var obj = {};
        for (var k in item) {
            obj[k] = item[k];
        }
        out.push(obj);
    }
    return out;
}

// test case

var original = [
    {'a' : 1},
    {'b' : 2}
    ];

var copy = deepCopy(original);

// change value in copy
copy[0]['a'] = 'not 1';

// original[0]['a'] still equals 1

Solusi ini mengulangi nilai-nilai array, kemudian mengulangi kunci objek, menyimpan yang terakhir ke objek baru, dan kemudian mendorong objek baru itu ke array baru.

Lihat jsfiddle . Catatan: sederhana .slice()atau [].concat()tidak cukup untuk objek dalam array.

bozdoz
sumber
terima kasih atas jawabannya, tetapi Anda harus menyoroti kekurangan dari jawabannya. Itu tidak berfungsi ketika benda memiliki benda di dalamnya .. kan?
Harsh
itu akan membuat salinan dangkal. bukan deep
sultan aslam
Anda perlu menambahkan rekursi di suatu tempat
DGoiko
6

Extend JQuery berfungsi dengan baik, hanya Anda perlu menentukan bahwa Anda mengkloning array daripada objek ( perhatikan [] alih-alih {} sebagai parameter ke metode extended ):

var clonedNodesArray = jQuery.extend([], nodesArray);
Stef
sumber
2
Hmm, jika Anda downvote ini, bisakah Anda menambahkan komentar tentang mengapa Anda melakukannya? Atau bisakah Anda pertama kali mencoba kode dan melihat apakah itu berfungsi atau tidak? Terima kasih;)
Stef
1
Setelah mengubah objek dalam array pertama, objek dalam array kedua akan dimodifikasi, jadi tidak ok.
Spikolynn
6

Metode ini sangat sederhana dan Anda dapat memodifikasi klon Anda tanpa mengubah array asli.

// Original Array
let array = [{name: 'Rafael'}, {name: 'Matheus'}];

// Cloning Array
let clone = array.map(a => {return {...a}})

// Editing the cloned array
clone[1].name = 'Carlos';


console.log('array', array)
// [{name: 'Rafael'}, {name: 'Matheus'}]

console.log('clone', clone)
// [{name: 'Rafael'}, {name: 'Carlos'}]

Rafael Grilli
sumber
1
Ini melakukan salinan dangkal yang dalamnya dua level, sedangkan [...oldArray]dan oldArray.slice(0)melakukan salinan yang dangkal satu tingkat. Jadi ini sangat berguna, tetapi bukan klon penuh dalam yang sebenarnya.
Ben Wheeler
true deep clone dapat dilakukan menggunakan lodash.clonedeepdari npm
revelt
5

Seperti Daniel Lew sebutkan, grafik siklik memiliki beberapa masalah. Jika saya punya masalah ini saya akan menambahkan khususclone() metode ke objek bermasalah atau ingat objek yang sudah saya salin.

Saya akan melakukannya dengan variabel copyCountyang bertambah 1 setiap kali Anda menyalin kode Anda. Objek yang memiliki copyCountproses copy yang lebih rendah dari saat ini disalin. Jika tidak, salinan yang sudah ada harus dirujuk. Ini membuatnya perlu untuk menghubungkan dari aslinya ke salinannya.

Masih ada satu masalah: Memori. Jika Anda memiliki referensi ini dari satu objek ke objek lain, kemungkinan peramban tidak dapat membebaskan objek-objek tersebut, karena mereka selalu dirujuk dari suatu tempat. Anda harus membuat langkah kedua di mana Anda mengatur semua referensi-salinan ke Null. (Jika Anda melakukan ini, Anda tidak harus memiliki copyCounttetapi boolean isCopiedakan cukup, karena Anda dapat mengatur ulang nilai di pass kedua.)

Georg Schölly
sumber
4

Array.slice dapat digunakan untuk menyalin array atau bagian dari array .. http://www.devguru.com/Technologies/Ecmascript/Quickref/Slice.html Ini akan bekerja dengan string dan angka .. - mengubah string dalam satu array tidak akan mempengaruhi yang lain - tetapi objek masih hanya disalin oleh referensi sehingga perubahan ke objek yang direferensikan dalam satu array akan mempengaruhi array lainnya.

Berikut ini adalah contoh dari manajer undo JavaScript yang dapat bermanfaat untuk ini: http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx

markt
sumber
Aku tahu. Alasan saya ingin menerapkan ini adalah karena saya mencoba untuk menyelesaikan masalah CSP dengan backtracking. Saya berpikir bahwa salah satu cara menerapkan backtracking bisa seperti "mengambil snapshots" keadaan penugasan variabel dengan ... mengkloning snapshots tersebut ke dalam stack.
wallyqs
... dan mungkin itu ide yang sangat buruk.
wallyqs
Pendekatan itu dapat memiliki komplikasi sinkronisasi lainnya :) .. Bagaimana Anda tahu array tidak sedang diubah saat Anda mengambil snapshot?
tandai
Menambahkan tautan ke artikel di mana penulis menerapkan undo manager sederhana menggunakan javascript ..
markt
4

Pendekatan saya:

var temp = { arr : originalArray };
var obj = $.extend(true, {}, temp);
return obj.arr;

memberi saya klon yang bagus, bersih, dalam dari array asli - dengan tidak ada objek yang dirujuk kembali ke aslinya :-)

nebula
sumber
Ini adalah solusi terbaik menggunakan jquery. pendek dan manis.
John Henckel
1
Saya melakukan tes kinerja dan solusi ini tampaknya kira-kira 2x lebih cepat daripada solusi JSON.stringify.
meehocz
4

lodash memiliki cloneDeepfungsi untuk tujuan ini:

var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
DicBrus
sumber
4

Jika Anda ingin menerapkan klon dalam, gunakan JSON.parse (JSON.stringify ({} atau []) Anda)

const myObj ={
    a:1,
    b:2,
    b:3
}

const deepClone=JSON.parse(JSON.stringify(myObj));
deepClone.a =12;
console.log("deepClone-----"+myObj.a);
const withOutDeepClone=myObj;
withOutDeepClone.a =12;
console.log("withOutDeepClone----"+myObj.a);

sudheer nunna
sumber
3

forget eval () (adalah fitur JS yang paling banyak disalahgunakan dan membuat kodenya lambat) dan slice (0) (hanya berfungsi untuk tipe data sederhana)

Ini solusi terbaik bagi saya:

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

Saya cukup frustrasi dengan masalah ini. Tampaknya masalah muncul ketika Anda mengirim Array umum ke metode $ .extend. Jadi, untuk memperbaikinya, saya menambahkan sedikit centang, dan berfungsi dengan baik dengan array umum, array jQuery, dan objek apa pun.

jQuery.extend({
    deepclone: function(objThing) {
        // return jQuery.extend(true, {}, objThing);
        /// Fix for arrays, without this, arrays passed in are returned as OBJECTS! WTF?!?!
        if ( jQuery.isArray(objThing) ) {
            return jQuery.makeArray( jQuery.deepclone($(objThing)) );
        }
        return jQuery.extend(true, {}, objThing);
    },
});

Meminta menggunakan:

var arrNewArrayClone = jQuery.deepclone(arrOriginalArray);
// Or more simply/commonly
var arrNewArrayClone = $.deepclone(arrOriginalArray);
Rem
sumber
deepclone? Saya menggunakan jquery-1.9.1 dan tidak mendukung metode ini. Apakah ini metode versi yang lebih modern?
user5260143
@ user2783091 ia memperluas JQuery untuk menambahkan fungsi itu. Ini bukan sesuatu yang keluar dari kotak
JorgeeFG
3

Ini sangat menyalin array, objek, nilai null dan skalar lainnya, dan juga sangat menyalin setiap properti pada fungsi non-asli (yang sangat jarang tetapi mungkin). (Untuk efisiensi, kami tidak mencoba menyalin properti non-numerik pada array.)

function deepClone (item) {
  if (Array.isArray(item)) {
    var newArr = [];
    for (var i = item.length; i-- > 0;) {
      newArr[i] = deepClone(item[i]);
    }
    return newArr;
  }
  if (typeof item === 'function' && !(/\(\) \{ \[native/).test(item.toString())) {
    var obj;
    eval('obj = '+ item.toString());
    for (var k in item) {
      obj[k] = deepClone(item[k]);
    }
    return obj;
  }
  if (item && typeof item === 'object') {
    var obj = {};
    for (var k in item) {
      obj[k] = deepClone(item[k]);
    }
    return obj;
  }
  return item;
}
Brett Zamir
sumber
3

Saya menggunakan metode ECMAScript 6 Object.assign baru :

let oldObject = [1,3,5,"test"];
let newObject = Object.assign({}, oldObject);

argumen pertama dari metode ini adalah array yang akan diperbarui, kami melewatkan objek kosong karena kami ingin memiliki objek baru.

kita juga bisa menggunakan sintaks ini, yang sama tetapi lebih pendek:

let newObject = [...oldObject];
Chtiwi Malek
sumber
Perhatikan bahwa pendekatan ini hanya akan menyalin referensi untuk array dan objek dalam array, dan tidak akan membuat salinan baru dari ini. Harapkan ini untuk memecah untuk struktur multidimensi.
Ben Wheeler
2

Kita dapat menemukan metode Array rekursif sederhana untuk mengkloning array multidimensi. Sementara objek dalam array bersarang tetap referensi ke objek yang sesuai dalam array sumber, array tidak akan.

Array.prototype.clone = function(){
  return this.map(e => Array.isArray(e) ? e.clone() : e);
};

var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ],
    brr = arr.clone();
brr[4][2][1] = "two";
console.log(JSON.stringify(arr));
console.log(JSON.stringify(brr));

Redu
sumber
2

Dalam JavaScript, array dan salin objek mengubah nilai asal, jadi Salinan yang dalam adalah solusi untuk ini.

Salinan dalam berarti benar-benar membuat array baru dan menyalin nilai-nilai, karena apa pun yang terjadi padanya tidak akan pernah memengaruhi yang asli.

JSON.parsedan JSON.stringifymerupakan cara terbaik dan sederhana untuk menyalin. The JSON.stringify()Metode mualaf nilai JavaScript untuk JSON string.The JSON.parse()metode mem-parsing string JSON, membangun nilai JavaScript atau objek yang dijelaskan oleh string.

// Klon Dalam

let a = [{ x:{z:1} , y: 2}];
let b = JSON.parse(JSON.stringify(a));
b[0].x.z=0

console.log(JSON.stringify(a)); //[{"x":{"z":1},"y":2}]
console.log(JSON.stringify(b)); // [{"x":{"z":0},"y":2}]

Untuk lebih jelasnya: Baca Di Sini

Bijay Rai
sumber
1
Ini solusi terbaik. Terima kasih.
Nikolay
1

dengan jQuery:

var target= [];
$.each(source, function() {target.push( $.extend({},this));});
lujan99
sumber
1

Kode berikut akan melakukan penyalinan dalam objek dan array secara rekursif :

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

Sumber

Franck Dernoncourt
sumber
arguments.calleetidak tersedia dalam mode ketat dan memiliki masalah kinerja sebaliknya.
Brett Zamir
0

Saya pikir berhasil menulis metode generik kloning mendalam setiap struktur JavaScript terutama menggunakan Object.createyang didukung di semua browser modern. Kodenya seperti ini:

function deepClone (item) {
  if (Array.isArray(item)) {
    var newArr = [];

    for (var i = item.length; i-- !== 0;) {
      newArr[i] = deepClone(item[i]);
    }

    return newArr;
  }
  else if (typeof item === 'function') {
    eval('var temp = '+ item.toString());
    return temp;
  }
  else if (typeof item === 'object')
    return Object.create(item);
  else
    return item;
}
ozantunca
sumber
Object.createakan memperlakukan itemsebagai prototipe objek, tetapi itu berbeda dari kloning. Jika itemdiubah, perubahan akan tercermin dalam "klon" dan sebaliknya. Pendekatan ini tidak berhasil.
Brett Zamir
0

Untuk mengkloning objek juga saya hanya akan menyarankan ECMAScript 6 reduce():

const newArray=myArray.reduce((array, element)=>array.push(Object.assign({}, element)), []);

Tapi terus terang saya lebih suka jawaban @dinodsaurus. Saya hanya menempatkan versi ini di sini sebagai opsi lain, tetapi secara pribadi saya akan menggunakan map()seperti yang disarankan oleh @dododsaurus.

Garret Wilson
sumber
0
       var game_popularity = [
            { game: "fruit ninja", popularity: 78 },
            { game: "road runner", popularity: 20 },
            { game: "maze runner", popularity: 40 },
            { game: "ludo", popularity: 75 },
            { game: "temple runner", popularity: 86 }
        ];
        console.log("sorted original array before clonning");
        game_popularity.sort((a, b) => a.popularity < b.popularity);
        console.log(game_popularity);


        console.log("clone using object assign");
        const cl2 = game_popularity.map(a => Object.assign({}, a));
        cl2[1].game = "clash of titan";
        cl2.push({ game: "logan", popularity: 57 });
        console.log(cl2);


        //adding new array element doesnt reflect in original array
        console.log("clone using concat");
        var ph = []
        var cl = ph.concat(game_popularity);

        //copied by reference ?
        cl[0].game = "rise of civilization";

        game_popularity[0].game = 'ping me';
        cl.push({ game: "angry bird", popularity: 67 });
        console.log(cl);

        console.log("clone using ellipses");
        var cl3 = [...game_popularity];
        cl3.push({ game: "blue whale", popularity: 67 });
        cl3[2].game = "harry potter";
        console.log(cl3);

        console.log("clone using json.parse");
        var cl4 = JSON.parse(JSON.stringify(game_popularity));
        cl4.push({ game: "home alone", popularity: 87 });
        cl4[3].game ="lockhead martin";
        console.log(cl4);

        console.log("clone using Object.create");
        var cl5 = Array.from(Object.create(game_popularity));
        cl5.push({ game: "fish ville", popularity: 87 });
        cl5[3].game ="veto power";
        console.log(cl5);


        //array function
        console.log("sorted original array after clonning");
        game_popularity.sort((a, b) => a.popularity < b.popularity);
        console.log(game_popularity);


        console.log("Object.assign deep clone object array");
        console.log("json.parse deep clone object array");
        console.log("concat does not deep clone object array");
        console.log("ellipses does not deep clone object array");
        console.log("Object.create does not deep clone object array");


        Output:


        sorted original array before clonning
        [ { game: 'temple runner', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 } ]
        clone using object assign
        [ { game: 'temple runner', popularity: 86 },
        { game: 'clash of titan', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'logan', popularity: 57 } ]
        clone using concat
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'angry bird', popularity: 67 } ]
        clone using ellipses
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'blue whale', popularity: 67 } ]
        clone using json.parse
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'lockhead martin', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'home alone', popularity: 87 } ]
        clone using Object.create
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'veto power', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'fish ville', popularity: 87 } ]
        sorted original array after clonning
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'veto power', popularity: 40 },
        { game: 'road runner', popularity: 20 } ]

        Object.assign deep clone object array
        json.parse deep clone object array
        concat does not deep clone object array
        ellipses does not deep clone object array
        Object.create does not deep clone object array
sangram
sumber