web-dev-qa-db-fra.com

Mise à jour des attributs d'objet JavaScript à partir d'un autre objet

Je veux mettre à jour un objet qui pourrait ressembler à ceci:

currentObject = {
    someValue : "value",
    myObject : {
        attribute1 : "foo",
        attribute2 : "bar"
    }
};

.. avec un objet contenant des modifications, à savoir:

updateObject = {
    myObject : {
        attribute2 : "hello world"
    }
};

A la fin, j'aimerais que currentObject soit mis à jour de sorte que:

currentObject.myObject.attribute2 == "hello world"

Cela devrait également être possible pour d’autres objets. Comme solution, j’ai pensé à parcourir l’objet et à prendre en charge l’espace de noms. Mais je me demande s’il existe une solution facile à ce problème en utilisant une bibliothèque telle que jQuery ou prototype.

23
Luca Hofmann
function update(obj/*, …*/) {
    for (var i=1; i<arguments.length; i++) {
        for (var prop in arguments[i]) {
            var val = arguments[i][prop];
            if (typeof val == "object") // this also applies to arrays or null!
                update(obj[prop], val);
            else
                obj[prop] = val;
        }
    }
    return obj;
}

devrait faire l'affaire: update(currentObject, updateObject). Vous voudrez peut-être ajouter des contrôles de type, tels que Object(obj) === obj pour étendre uniquement les objets réels avec des objets réels, utilisez une boucle correcte pour les tableaux ou les tests hasOwnProperty.

8
Bergi

Je suggère d'utiliser underscore.js (ou mieux, lo-dash) extend :

_.extend (destination, * sources)

Copiez toutes les propriétés des objets source sur l'objet de destination Et renvoyez-les.il est dans l'ordre, De sorte que la dernière source remplacera les propriétés du même nom dans les arguments précédents de.

_.extend({name: 'moe'}, {age: 50});
=> {name: 'moe', age: 50}
16
bluehallu

Une implémentation simple ressemblerait à ceci.

function copyInto(target /*, source1, sourcen */) {
    if (!target || typeof target !== "object")
        target = {};

    if (arguments.length < 2)
        return target;

    for (var len = arguments.length - 1; len > 0; len--)
        cloneObject(arguments[len-1], arguments[len]);

    return target;
}

function cloneObject(target, source) {
    if (!source || !target || typeof source !== "object" || typeof target !== "object")
        throw new TypeError("Invalid argument");

    for (var p in source)
        if (source.hasOwnProperty(p))
            if (source[p] && typeof source[p] === "object")
                if (target[p] && typeof target[p] === "object")
                    cloneObject(target[p], source[p]);
                else
                    target[p] = source[p];
            else 
                target[p] = source[p];
}

Cela suppose qu'aucune propriété héritée ne doit être clonée. En outre, il ne vérifie pas des objets tels que les objets DOM ou les primitives en boîte.

Nous devons parcourir les arguments en sens inverse pour que la copie soit faite dans une matière de droite à gauche.

Ensuite, nous créons une fonction cloneObject distincte pour gérer la copie récursive d'objets imbriqués de manière à ne pas interférer avec la copie de droite à gauche des arguments de l'objet d'origine.

Cela garantit également que la cible initiale est un objet simple.

La fonction cloneObject émettra une erreur si un non-objet lui a été transmis.

1
user1689386

Voici un exemple Object.keys et récursif:

// execute object update function
update(currentObject, updateObject)

// instantiate object update function
function update (targetObject, obj) {
  Object.keys(obj).forEach(function (key) {

    // delete property if set to undefined or null
    if ( undefined === obj[key] || null === obj[key] ) {
      delete targetObject[key]
    }

    // property value is object, so recurse
    else if ( 
        'object' === typeof obj[key] 
        && !Array.isArray(obj[key]) 
    ) {

      // target property not object, overwrite with empty object
      if ( 
        !('object' === typeof targetObject[key] 
        && !Array.isArray(targetObject[key])) 
      ) {
        targetObject[key] = {}
      }

      // recurse
      update(targetObject[key], obj[key])
    }

    // set target property to update property
    else {
      targetObject[key] = obj[key]
    }
  })
}

Démo de JSFiddle .

0
bloodyKnuckles