HTML5 comprend un moyen de créer de profondes clones d'objets. Elle ne fonctionne que pour certains types intégrés, mais c'est beaucoup plus souple que l'utilisation de JSON: l' interne structurée clone algorithme prend également en charge les Dates, les expressions régulières, Fichiers, des Gouttes, des listes de fichiers, ImageDatas, Matrices creuses, les types définis dans d'autres spécifications comme les Tableaux Typés, et récursive/cyclique des structures.
Malheureusement, cette fonctionnalité n'est pas directement exposée à travers une API. Voici deux façons structuré que clones peuvent être créés. Les deux ont des inconvénients qui les rendent impropres à beaucoup de cas. Nous espérons qu'il sera un jour possible de créé structuré clones sans effets secondaires.
history.pushState()
et history.replaceState()
à la fois de créer un structurés clone de leur premier argument, et d'affecter cette valeur à history.state
. Vous pouvez l'utiliser pour créer un structurés clone de n'importe quel objet comme ceci:
function structuredClone(obj) {
var oldState = history.state;
history.replaceState(obj);
var clonedObj = history.state;
history.replaceState(oldState);
return clonedObj;
}
Exemple d'Utilisation (jsfiddle)
var original = { date: new Date(), number: Math.random() };
original.self = original;
var clone = structuredClone(original);
// They're different objects:
console.log(original !== clone);
console.log(original.date !== clone.date);
// They're cyclical:
console.log(original.self === original);
console.log(clone.self === clone);
// They contain equivalent values:
console.log(original.number === clone.number);
console.log(Number(original.date) === Number(clone.date));
Cela ne devrait pas vous laisser de trace dans l'historique du navigateur, mais il est très lent et peut entraîner le navigateur pour commencer à afficher brièvement son chargement de l'animation. Si vous tentez de clone de nombreux objets à la fois, il peut provoquer le navigateur (y compris les autres onglets et fenêtres) ne répond plus jusqu'à ce que le clonage est terminée. (Le clonage n'est pas lent; c'est un des effets secondaires de la manipulation de l'histoire.)
L'alternative est d'appeler l' window.postMessage
méthode pour envoyer un message contenant l'objet cible de l' window
, puis de les écouter pour l' message
événement contenant l'objet cloné. Malheureusement, ce n'est intrinsèquement asynchrone.
Si asynchrone clonage est acceptable, voici un asyncStructuredClone(original, callback(clone))
fonction qui permettra de produire structuré un clone d'un objet cible et de le passer à votre rappel. Une exception sera levée si vous tentative de cloner un objet non pris en charge.
var pendingCallbacks = {};
window.addEventListener('message', function(e) {
var cloneId = e.data.cloneId,
clonedValue = e.data.value;
if (e.source === window && cloneId && cloneId in pendingCallbacks) {
var callback = pendingCallbacks[cloneId];
delete pendingCallbacks[cloneId];
callback(clonedValue);
}
});
var asyncStructuredClone = function(o, callback) {
var cloneId = String(Math.random());
pendingCallbacks[cloneId] = callback;
window.postMessage({ value: o, cloneId: cloneId }, '*');
};
Exemple d'Utilisation (jsfiddle)
var original = { date: new Date(), number: Math.random() };
original.self = original;
asyncStructuredClone(original, function(clone) {
// They're different objects:
console.log(original !== clone);
console.log(original.date !== clone.date);
// They're cyclical:
console.log(original.self === original);
console.log(clone.self === clone);
// They contain equivalent values:
console.log(original.number === clone.number);
console.log(Number(original.date) === Number(clone.date));
});