Kloning Terstruktur
Standar HTML mencakup algoritma kloning / serialisasi terstruktur internal yang dapat membuat klon objek dalam. Ini masih terbatas pada tipe bawaan tertentu, tetapi selain beberapa jenis yang didukung oleh JSON, ini juga mendukung Tanggal, RegExps, Peta, Set, Blob, FileLists, ImageDatas, Array yang jarang, Array yang Diketik, dan mungkin lebih banyak di masa depan . Itu juga mempertahankan referensi dalam data kloning, memungkinkannya untuk mendukung struktur siklus dan rekursif yang akan menyebabkan kesalahan untuk JSON.
Dukungan di Node.js: Eksperimental π
The v8
modul Node.js saat ini (per Node 11) memperlihatkan serialisasi API terstruktur secara langsung , tetapi fungsi ini masih ditandai sebagai "eksperimental", dan tunduk pada perubahan atau penghapusan dalam versi masa depan. Jika Anda menggunakan versi yang kompatibel, kloning objek semudah:
const v8 = require('v8');
const structuredClone = obj => {
return v8.deserialize(v8.serialize(obj));
};
Dukungan Langsung di Peramban: Mungkin Akhirnya? π
Browser saat ini tidak menyediakan antarmuka langsung untuk algoritma kloning terstruktur, tetapi structuredClone()
fungsi global telah dibahas dalam whatwg / html # 793 di GitHub . Seperti yang diusulkan saat ini, menggunakannya untuk sebagian besar tujuan akan sesederhana:
const clone = structuredClone(original);
Kecuali jika ini dikirimkan, implementasi klon terstruktur browser hanya diekspos secara tidak langsung.
Pemecahan Masalah Asinkron: Dapat Digunakan. π
Cara overhead yang lebih rendah untuk membuat klon terstruktur dengan API yang ada adalah memposting data melalui satu port dari MessageChannels . Port lain akan memancarkan message
acara dengan klon terstruktur dari terlampir .data
. Sayangnya, mendengarkan acara-acara ini selalu asinkron, dan alternatif sinkron kurang praktis.
class StructuredCloner {
constructor() {
this.pendingClones_ = new Map();
this.nextKey_ = 0;
const channel = new MessageChannel();
this.inPort_ = channel.port1;
this.outPort_ = channel.port2;
this.outPort_.onmessage = ({data: {key, value}}) => {
const resolve = this.pendingClones_.get(key);
resolve(value);
this.pendingClones_.delete(key);
};
this.outPort_.start();
}
cloneAsync(value) {
return new Promise(resolve => {
const key = this.nextKey_++;
this.pendingClones_.set(key, resolve);
this.inPort_.postMessage({key, value});
});
}
}
const structuredCloneAsync = window.structuredCloneAsync =
StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);
Contoh Penggunaan:
const main = async () => {
const original = { date: new Date(), number: Math.random() };
original.self = original;
const clone = await structuredCloneAsync(original);
// They're different objects:
console.assert(original !== clone);
console.assert(original.date !== clone.date);
// They're cyclical:
console.assert(original.self === original);
console.assert(clone.self === clone);
// They contain equivalent values:
console.assert(original.number === clone.number);
console.assert(Number(original.date) === Number(clone.date));
console.log("Assertions complete.");
};
main();
Solusi Sinkron: Mengerikan! π€’
Tidak ada opsi yang baik untuk membuat klon terstruktur secara serempak. Berikut adalah beberapa peretasan yang tidak praktis.
history.pushState()
dan history.replaceState()
keduanya membuat klon terstruktur dari argumen pertama mereka, dan menetapkan nilai itu history.state
. Anda dapat menggunakan ini untuk membuat klon terstruktur dari objek apa pun seperti ini:
const structuredClone = obj => {
const oldState = history.state;
history.replaceState(obj, null);
const clonedObj = history.state;
history.replaceState(oldState, null);
return clonedObj;
};
Contoh Penggunaan:
'use strict';
const main = () => {
const original = { date: new Date(), number: Math.random() };
original.self = original;
const clone = structuredClone(original);
// They're different objects:
console.assert(original !== clone);
console.assert(original.date !== clone.date);
// They're cyclical:
console.assert(original.self === original);
console.assert(clone.self === clone);
// They contain equivalent values:
console.assert(original.number === clone.number);
console.assert(Number(original.date) === Number(clone.date));
console.log("Assertions complete.");
};
const structuredClone = obj => {
const oldState = history.state;
history.replaceState(obj, null);
const clonedObj = history.state;
history.replaceState(oldState, null);
return clonedObj;
};
main();
Meskipun sinkron, ini bisa sangat lambat. Itu menimbulkan semua overhead yang terkait dengan memanipulasi riwayat browser. Memanggil metode ini berulang kali dapat menyebabkan Chrome menjadi tidak responsif sementara.
The Notification
konstruktor menciptakan klon terstruktur data yang terkait. Itu juga mencoba untuk menampilkan pemberitahuan browser kepada pengguna, tetapi ini akan gagal secara diam-diam kecuali Anda telah meminta izin pemberitahuan. Jika Anda memiliki izin untuk tujuan lain, kami akan segera menutup pemberitahuan yang kami buat.
const structuredClone = obj => {
const n = new Notification('', {data: obj, silent: true});
n.onshow = n.close.bind(n);
return n.data;
};
Contoh Penggunaan:
'use strict';
const main = () => {
const original = { date: new Date(), number: Math.random() };
original.self = original;
const clone = structuredClone(original);
// They're different objects:
console.assert(original !== clone);
console.assert(original.date !== clone.date);
// They're cyclical:
console.assert(original.self === original);
console.assert(clone.self === clone);
// They contain equivalent values:
console.assert(original.number === clone.number);
console.assert(Number(original.date) === Number(clone.date));
console.log("Assertions complete.");
};
const structuredClone = obj => {
const n = new Notification('', {data: obj, silent: true});
n.close();
return n.data;
};
main();