Bagaimana cara mengkloning instance kelas Javascript menggunakan ES6.
Saya tidak tertarik dengan solusi berdasarkan jquery atau $ extends.
Saya telah melihat diskusi yang cukup lama tentang kloning objek yang menunjukkan bahwa masalahnya cukup rumit, tetapi dengan ES6 solusi yang sangat sederhana muncul dengan sendirinya - saya akan meletakkannya di bawah dan melihat apakah orang menganggapnya memuaskan.
edit: disarankan bahwa pertanyaan saya adalah duplikat; Saya melihat jawaban itu tetapi usianya 7 tahun dan melibatkan jawaban yang sangat rumit menggunakan pra-ES6 js. Saya menyarankan bahwa pertanyaan saya, yang memungkinkan untuk ES6, memiliki solusi yang jauh lebih sederhana.
Object
yang digunakan sebagai pemegang data. Yang satu ini tentang ES6class
es dan masalah untuk tidak kehilangan informasi jenis kelas. Ini membutuhkan solusi yang berbeda.Jawaban:
Itu rumit; Saya sudah mencoba banyak! Pada akhirnya, satu baris ini berfungsi untuk instance kelas ES6 khusus saya:
let clone = Object.assign(Object.create(Object.getPrototypeOf(orig)), orig)
Ini menghindari pengaturan prototipe karena mereka mengatakan itu sangat memperlambat kode.
Ini mendukung simbol tetapi tidak sempurna untuk getter / setter dan tidak bekerja dengan properti non-enumerable (lihat Object.assign () docs ). Juga, kloning kelas internal dasar (seperti Array, Date, RegExp, Map, dll.) Sayangnya sering kali membutuhkan penanganan individu.
Kesimpulan: Ini berantakan. Mari berharap suatu hari akan ada fungsi klon asli dan bersih.
sumber
const clone = Object.assign( {}, instanceOfBlah ); Object.setPrototypeOf( clone, Blah.prototype );
Perhatikan karakteristik Object.assign : ia melakukan penyalinan dangkal dan tidak menyalin metode kelas.
Jika Anda menginginkan salinan yang mendalam atau kontrol yang lebih besar atas salinan tersebut maka ada fungsi klon lodash .
sumber
Object.create
membuat objek baru dengan prototipe tertentu, mengapa tidak lalu sajaconst clone = Object.assign(Object.create(instanceOfBlah), instanceOfBlah)
. Metode kelas juga akan disalin.Blah.prototype != instanceOfBlah
. Anda harus menggunakanObject.getPrototypeOf(instanceOfBlah)
Tidak disarankan untuk membuat ekstensi Prototipe, Ini akan mengakibatkan masalah saat Anda akan melakukan tes pada kode / komponen Anda. Kerangka pengujian unit tidak akan secara otomatis mengasumsikan ekstensi prototipe Anda. Jadi ini bukanlah praktik yang baik. Ada lebih banyak penjelasan tentang ekstensi prototipe di sini. Mengapa memperluas objek asli merupakan praktik yang buruk?
Untuk mengkloning objek di JavaScript tidak ada cara yang sederhana atau mudah. Berikut ini contoh pertama yang menggunakan "Shallow Copy":
1 -> Klon dangkal:
class Employee { constructor(first, last, street) { this.firstName = first; this.lastName = last; this.address = { street: street }; } logFullName() { console.log(this.firstName + ' ' + this.lastName); } } let original = new Employee('Cassio', 'Seffrin', 'Street A, 23'); let clone = Object.assign({},original); //object.assing() method let cloneWithPrototype Object.create(Object.getPrototypeOf(original)), original) // the clone will inherit the prototype methods of the original. let clone2 = { ...original }; // the same of object assign but shorter sintax using "spread operator" clone.firstName = 'John'; clone.address.street = 'Street B, 99'; //will not be cloned
Hasil:
Perhatian: Jika instance memiliki closure sebagai propertinya sendiri, metode ini tidak akan membungkusnya. ( baca lebih lanjut tentang closures ) Dan plus, sub object "address" tidak akan di kloning.
tidak akan bekerja.
akan berfungsi, karena klon juga akan menyalin Prototipe-nya.
Untuk mengkloning array dengan Object.assign:
let cloneArr = array.map((a) => Object.assign({}, a));
Klon array menggunakan sintaks penyebaran ECMAScript:
let cloneArrSpread = array.map((a) => ({ ...a }));
2 -> Klon Dalam:
Untuk mengarsipkan referensi objek yang benar-benar baru, kita dapat menggunakan JSON.stringify () untuk mengurai objek asli sebagai string dan setelah mengurai kembali ke JSON.parse ().
let deepClone = JSON.parse(JSON.stringify(original));
Dengan deep clone, referensi ke alamat akan disimpan. Namun Prototipe deepClone akan dihilangkan, oleh karena itu deepClone.logFullName () tidak akan berfungsi.
3 -> perpustakaan pihak ke-3:
Pilihan lain akan menggunakan pustaka pihak ke-3 seperti loadash atau garis bawah. Mereka akan membuat objek baru dan menyalin setiap nilai dari aslinya ke objek baru dengan menyimpan referensinya di memori.
Garis bawah: biarkan cloneUnderscore = _ (asli) .clone ();
Loadash clone: var cloneLodash = _.cloneDeep (asli);
Kelemahan dari lodash atau garis bawah adalah kebutuhan untuk memasukkan beberapa perpustakaan tambahan dalam proyek Anda. Bagaimanapun mereka adalah pilihan yang baik dan juga menghasilkan hasil kinerja tinggi.
sumber
{}
, klon tidak akan mewarisi metode prototipe apa pun dari aslinya.clone.logFullName()
tidak akan bekerja sama sekali. YangObject.assign( Object.create(Object.getPrototypeOf(eOriginal)), eOriginal)
Anda miliki sebelumnya baik-baik saja, mengapa Anda mengubahnya?Object.assign({},original)
, itu tidak berhasil.Satu kapal lagi:
Sebagian besar waktu ... (berfungsi untuk Date, RegExp, Map, String, Number, Array), btw, cloning string, number agak lucu.
let clone = new obj.constructor(...[obj].flat())
untuk kelas tersebut tanpa konstruktor salinan:
let clone = Object.assign(new obj.constructor(...[obj].flat()), obj)
sumber
class A { constructor() { this.x = 1; } y() { return 1; } } const a = new A(); const output = Object.getOwnPropertyNames(Object.getPrototypeOf(a)).concat(Object.getOwnPropertyNames(a)).reduce((accumulator, currentValue, currentIndex, array) => { accumulator[currentValue] = a[currentValue]; return accumulator; }, {});
sumber
Anda dapat menggunakan operator penyebaran, misalnya jika Anda ingin mengkloning sebuah objek bernama Obj:
let clone = { ...obj};
Dan jika Anda ingin mengubah atau menambahkan apa pun ke objek kloning:
let clone = { ...obj, change: "something" };
sumber