Quel est le meilleur moyen de cloner un objet dans node.js
par exemple. Je veux éviter la situation où:
var obj1 = {x: 5, y:5};
var obj2 = obj1;
obj2.x = 6;
console.log(obj1.x); // logs 6
L'objet peut très bien contenir des types complexes en tant qu'attributs, donc un simple for (var x dans obj1) ne résoudrait pas. Dois-je écrire moi-même un clone récursif ou y a-t-il quelque chose d'intégré que je ne vois pas?
Copie profonde à faible fioriture:
var obj2 = JSON.parse(JSON.stringify(obj1));
Attention: Cette solution est maintenant marquée comme obsolète dans le documentation de Node.js :
La méthode util._extend () n'a jamais été conçue pour être utilisée en dehors des modules internes de Node.js. La communauté a trouvé et utilisé de toute façon.
Il est obsolète et ne devrait pas être utilisé dans le nouveau code. JavaScript est livré avec une fonctionnalité intégrée très similaire via Object.assign ().
Réponse originale: :
Pour une copie peu profonde, utilisez la fonction intégrée util._extend()
du nœud.
var extend = require('util')._extend;
var obj1 = {x: 5, y:5};
var obj2 = extend({}, obj1);
obj2.x = 6;
console.log(obj1.x); // still logs 5
Le code source de la fonction _extend
du noeud est ici: https://github.com/joyent/node/blob/master/lib/util.js
exports._extend = function(Origin, add) {
// Don't do anything if add isn't an object
if (!add || typeof add !== 'object') return Origin;
var keys = Object.keys(add);
var i = keys.length;
while (i--) {
Origin[keys[i]] = add[keys[i]];
}
return Origin;
};
Je suis surpris que Object.assign
n'ait pas été mentionné.
let cloned = Object.assign({}, source);
Si disponible (par exemple Babel), vous pouvez utiliser le opérateur de propagation d'objet :
let cloned = { ... source };
Object.defineProperty(Object.prototype, "extend", {
enumerable: false,
value: function(from) {
var props = Object.getOwnPropertyNames(from);
var dest = this;
props.forEach(function(name) {
if (name in dest) {
var destination = Object.getOwnPropertyDescriptor(from, name);
Object.defineProperty(dest, name, destination);
}
});
return this;
}
});
Cela définira une méthode d'extension que vous pouvez utiliser. Le code vient de cet article.
var obj2 = JSON.parse(JSON.stringify(obj1));
Vous pouvez utiliser la fonction extend de JQuery:
var newClone= jQuery.extend({}, oldObject);
var deepClone = jQuery.extend(true, {}, oldObject);
Il existe aussi un plugin Node.js:
https://github.com/shimondoodkin/nodejs-clone-extend
Pour le faire sans JQuery ou Plugin, lisez ceci ici:
Départ nderscore.js . Il a à la fois clone et extend et de nombreuses autres fonctions très utiles.
Cela peut être utile: tilisation du module Underscore avec Node.js
Il existe quelques Node modules si vous ne voulez pas "lancer le vôtre". Celui-ci a l'air bien: https://www.npmjs.com/package/clone
On dirait qu'il gère toutes sortes de choses, y compris les références circulaires. De la page github :
cloner les objets de clonage, les tableaux, les objets Date et les objets RegEx. Tout est cloné de manière récursive, afin que vous puissiez cloner des dates dans des tableaux d'objets, par exemple. [...] Références circulaires? Oui!
Ce code est également une cause de travail. La méthode Object.create () crée un nouvel objet avec les propriétés et l’objet prototype spécifiés.
var obj1 = {x:5, y:5};
var obj2 = Object.create(obj1);
obj2.x; //5
obj2.x = 6;
obj2.x; //6
obj1.x; //5
Le moyen le plus simple et le plus rapide de cloner un objet dans NodeJS consiste à utiliser la méthode Object.keys (obj)
var a = {"a": "a11", "b": "avc"};
var b;
for(var keys = Object.keys(a), l = keys.length; l; --l)
{
b[ keys[l-1] ] = a[ keys[l-1] ];
}
b.a = 0;
console.log("a: " + JSON.stringify(a)); // LOG: a: {"a":"a11","b":"avc"}
console.log("b: " + JSON.stringify(b)); // LOG: b: {"a":0,"b":"avc"}
La méthode Object.keys requiert JavaScript 1.8.5; nodeJS v0.4.11 supporte cette méthode
mais bien sûr, les objets imbriqués doivent implémenter une fonction récursive
Une autre solution consiste à utiliser le JSON natif (implémenté dans JavaScript 1.7), mais il est beaucoup plus lent (environ 10 fois plus lent) que le précédent.
var a = {"a": i, "b": i*i};
var b = JSON.parse(JSON.stringify(a));
b.a = 0;
Il existe également un projet sur Github qui vise à être un port plus direct de la jQuery.extend()
:
https://github.com/dreamerslab/node.extend
Un exemple, modifié à partir de docs jQuery :
var extend = require('node.extend');
var object1 = {
Apple: 0,
banana: {
weight: 52,
price: 100
},
cherry: 97
};
var object2 = {
banana: {
price: 200
},
durian: 100
};
var merged = extend(object1, object2);
À la recherche d'une véritable option de clonage, je suis tombé sur le lien ridicule de cet outil:
http://my.opera.com/GreyWyvern/blog/show.dml/1725165
J'ai modifié la solution sur cette page afin que la fonction attachée au prototype Object
ne soit pas énumérable. Voici mon résultat:
Object.defineProperty(Object.prototype, 'clone', {
enumerable: false,
value: 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;
}
});
Espérons que cela aide aussi quelqu'un d'autre. Notez qu'il y a quelques réserves ... particulièrement avec les propriétés nommées "clone". Cela fonctionne bien pour moi. Je ne prends aucun crédit pour l'écrire. Encore une fois, j'ai seulement changé la façon dont il était défini.
Vous pouvez également utiliser SugarJS dans NodeJS.
Ils ont une fonctionnalité de clone très propre: http://sugarjs.com/api/Object/clone
Aucune des réponses ne m'a satisfait, plusieurs ne fonctionnent pas ou ne sont que des clones superficiels. Les réponses de @ clint-harris et l'utilisation de JSON.parse/stringify sont bonnes mais assez lentes. J'ai trouvé un module qui effectue un clonage profond rapide: https://github.com/AlexeyKupershtokh/node-v8-clone
Il n'y a pas de méthode intégrée pour créer un véritable clone (copie complète) d'un objet dans node.js. Il y a quelques cas délicats Edge, vous devriez donc absolument utiliser une bibliothèque pour cela. J'ai écrit une telle fonction pour ma bibliothèque simpleoo . Vous pouvez utiliser la fonction deepCopy
sans utiliser d'autre élément de la bibliothèque (ce qui est assez petit) si vous n'en avez pas besoin. Cette fonction prend en charge le clonage de plusieurs types de données, y compris les tableaux, les dates et les expressions régulières. Elle prend également en charge les références récursives. Elle fonctionne également avec les objets dont les fonctions de constructeur ont des paramètres requis.
Voici le code:
//If Object.create isn't already defined, we just do the simple shim, without the second argument,
//since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
object_create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
/**
* Deep copy an object (make copies of all its object properties, sub-properties, etc.)
* An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
* that doesn't break if the constructor has required parameters
*
* It also borrows some code from http://stackoverflow.com/a/11621004/560114
*/
function deepCopy = function deepCopy(src, /* INTERNAL */ _visited) {
if(src == null || typeof(src) !== 'object'){
return src;
}
// Initialize the visited objects array if needed
// This is used to detect cyclic references
if (_visited == undefined){
_visited = [];
}
// Ensure src has not already been visited
else {
var i, len = _visited.length;
for (i = 0; i < len; i++) {
// If src was already visited, don't try to copy it, just return the reference
if (src === _visited[i]) {
return src;
}
}
}
// Add this object to the visited array
_visited.Push(src);
//Honor native/custom clone methods
if(typeof src.clone == 'function'){
return src.clone(true);
}
//Special cases:
//Array
if (Object.prototype.toString.call(src) == '[object Array]') {
//[].slice(0) would soft clone
ret = src.slice();
var i = ret.length;
while (i--){
ret[i] = deepCopy(ret[i], _visited);
}
return ret;
}
//Date
if (src instanceof Date) {
return new Date(src.getTime());
}
//RegExp
if (src instanceof RegExp) {
return new RegExp(src);
}
//DOM Element
if (src.nodeType && typeof src.cloneNode == 'function') {
return src.cloneNode(true);
}
//If we've reached here, we have a regular object, array, or function
//make sure the returned object has the same prototype as the original
var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
if (!proto) {
proto = src.constructor.prototype; //this line would probably only be reached by very old browsers
}
var ret = object_create(proto);
for(var key in src){
//Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
//For an example of how this could be modified to do so, see the singleMixin() function
ret[key] = deepCopy(src[key], _visited);
}
return ret;
};
npm install node-v8-clone
Le cloner le plus rapide, il ouvre la méthode de clonage native de node.js
var clone = require('node-v8-clone').clone;
var newObj = clone(obj, true); //true - deep recursive clone
Si vous utilisez coffee-script, c'est aussi simple que:
newObject = {}
newObject[key] = value for own key,value of oldObject
Bien que ce ne soit pas un clone profond.