95 votes

Nodejs : comment cloner un objet

Si je clone un tableau, j'utilise cloneArr = arr.slice()

Je veux savoir comment cloner un objet dans nodejs.

187voto

Kato Points 12210

Pour les utilitaires et les classes où il n'est pas nécessaire d'exploiter chaque goutte de performance, je triche souvent et j'utilise simplement JSON pour effectuer une copie profonde :

function clone(a) {
   return JSON.parse(JSON.stringify(a));
}

Ce n'est pas la seule réponse ou la réponse la plus élégante ; toutes les autres réponses doivent être prises en compte pour les goulets d'étranglement de la production. Cependant, il s'agit d'une solution rapide et sale, assez efficace, et utile dans la plupart des situations où je clonerais un simple hachage de propriétés.

0 votes

Bonne réponse mais notez que "profond" est relatif. Il ne suivra pas les références à d'autres objets.

2 votes

@djechlin Bien sûr que oui. Essayez-le : jsfiddle.net/katowulf/E5jC3 (testé avec le nœud 0.10.11). Il ne sera pas capable de reconstituer des fonctions ou des données prototypiques, mais il obtient les valeurs autour juste bien.

14 votes

Ceci convertira les dates en chaînes de caractères

21voto

Clint Harris Points 7163

Il existe quelques modules Node si vous ne voulez pas "rouler vous-même". Celui-ci semble bon : https://www.npmjs.com/package/clone

Il semble qu'il gère toutes sortes de choses, y compris les références circulaires. De la github page :

clone maîtrise le clonage d'objets, de tableaux, d'objets Date et d'objets RegEx et RegEx. Tout est cloné de manière récursive, de sorte que vous pouvez cloner des dates dans des tableaux dans des objets, par exemple. [...] Des références circulaires ? Oui !

10voto

6502 Points 42700

Il est difficile de réaliser une opération de clonage générique mais utile car ce qui doit être cloné de manière récursive et ce qui doit être simplement copié dépend de la manière dont l'objet spécifique est censé fonctionner.

Quelque chose qui peut être utile est

function clone(x)
{
    if (x === null || x === undefined)
        return x;
    if (typeof x.clone === "function")
        return x.clone();
    if (x.constructor == Array)
    {
        var r = [];
        for (var i=0,n=x.length; i<n; i++)
            r.push(clone(x[i]));
        return r;
    }
    return x;
}

Dans ce code, la logique est la suivante

  • en cas de null o undefined renvoient simplement la même chose (le cas particulier est nécessaire parce que c'est une erreur d'essayer de voir si un clone est présente)
  • L'objet a-t-il un clone puis utiliser cette méthode
  • l'objet est un tableau ? alors faites une opération de clonage récursif
  • sinon, il suffit de retourner la même valeur

Cette fonction de clonage devrait permettre d'implémenter facilement des méthodes de clonage personnalisées... par exemple

function Point(x, y)
{
    this.x = x;
    this.y = y;

    ...
}

Point.prototype.clone = function()
{
    return new Point(this.x, this.y);
};

function Polygon(points, style)
{
    this.points = points;
    this.style = style;

    ...
}

Polygon.prototype.clone = function()
{
    return new Polygon(clone(this.points),
                       this.style);
};

Lorsque dans l'objet vous savez qu'une opération de clonage correcte pour un tableau spécifique est juste une copie superficielle, vous pouvez appeler values.slice() au lieu de clone(values) .

Par exemple, dans le code ci-dessus, je demande explicitement que le clonage d'un objet polygone clone les points, mais partage le même objet de style. Si je veux cloner l'objet de style aussi, je peux simplement passer la directive clone(this.style) .

1 votes

+1 pour avoir mentionné que les objets doivent implémenter .clone méthode eux-mêmes. C'est la meilleure façon de gérer le clonage des objets.

3 votes

if (x.clone) devrait être if (typeof x.clone === 'function')

0 votes

@YanickRochon : Merci, corrigé. Désolé, je n'ai pas remarqué ce commentaire avant...

9voto

Raynos Points 82706

Il n'existe pas de méthode native pour cloner des objets. Underscore implémente _.clone qui est un clone peu profond.

_.clone = function(obj) {
  return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};

Elle le tranche ou le prolonge.

Voici _.extend

// extend the obj (first parameter)
_.extend = function(obj) {
  // for each other parameter
  each(slice.call(arguments, 1), function(source) {
    // loop through all properties of the other objects
    for (var prop in source) {
      // if the property is not undefined then add it to the object.
      if (source[prop] !== void 0) obj[prop] = source[prop];
    }
  });
  // return the object (first parameter)
  return obj;
};

Extend itère simplement à travers tous les éléments et crée un nouvel objet avec les éléments qu'il contient.

Vous pouvez déployer votre propre implémentation naïve si vous le souhaitez.

function clone(o) {
  var ret = {};
  Object.keys(o).forEach(function (val) {
    ret[val] = o[val];
  });
  return ret;
}

Il existe de bonnes raisons d'éviter le clonage profond, car les fermetures ne peuvent pas être clonées.

J'ai personnellement posé une question sur deep cloning objects before et la conclusion à laquelle je suis arrivé est que tu ne le fais pas.

Je recommande d'utiliser underscore et c'est _.clone méthode pour les clones peu profonds

9voto

Olli K Points 159

Pour une copie superficielle, j'aime utiliser le modèle de réduction (généralement dans un module ou autre), comme ceci :

var newObject = Object.keys(original).reduce(function (obj, item) {
    obj[item] = original[item];
    return obj;
},{});

Voici un jsperf pour quelques unes des options : http://jsperf.com/shallow-copying

0 votes

Simple, élégant, brillant. J'attends avec impatience vos autres contributions à SO ^_^

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X