Vraag Hoe kan ik eigenschappen van twee JavaScript-objecten dynamisch samenvoegen?


Ik moet in staat zijn om twee (zeer eenvoudige) JavaScript-objecten tijdens runtime samen te voegen. Ik zou bijvoorbeeld graag willen:

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }

obj1.merge(obj2);

//obj1 now has three properties: food, car, and animal

Heeft iemand hier een script voor of weet het van een ingebouwde manier om dit te doen? Ik heb geen recursie nodig en ik hoef geen functies samen te voegen, alleen methoden op platte objecten.


1826


oorsprong


antwoorden:


Standaardmethode ECMAScript 2018

Je zou gebruiken objecten verspreiden:

let merged = {...obj1, ...obj2};

/** There's no limit to the number of objects you can merge.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};

ECMAScript 2015 (ES6) Standaardmethode

/* For the case in question, you would do: */
Object.assign(obj1, obj2);

/** There's no limit to the number of objects you can merge.
 *  All objects get merged into the first object. 
 *  Only the object in the first argument is mutated and returned.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);

(zien MDN JavaScript-referentie)


Methode voor ES5 en eerder

for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }

Merk op dat dit gewoon alle kenmerken van zal toevoegen obj2 naar obj1 wat misschien niet is wat je wilt als je het ongewijzigde nog steeds wilt gebruiken obj1.

Als je een raamwerk gebruikt dat je hele prototypes in de maling neemt, dan moet je liefhebber worden van cheques zoals hasOwnProperty, maar die code zal voor 99% van de gevallen werken.

Voorbeeldfunctie:

/**
 * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
 * @param obj1
 * @param obj2
 * @returns obj3 a new object based on obj1 and obj2
 */
function merge_options(obj1,obj2){
    var obj3 = {};
    for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
    for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
    return obj3;
}

1886



jQuery heeft hier ook een hulpprogramma voor: http://api.jquery.com/jQuery.extend/.

Afkomstig van de jQuery-documentatie:

// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options  = { validate: true, name: "bar" };
jQuery.extend(settings, options);

// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }

De bovenstaande code muteert de bestaand object genaamd settings.


Als u een wilt maken nieuw object zonder een van beide argumenten te wijzigen, gebruik dit:

var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };

/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);

// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.

1114



De Harmony ECMAScript 2015 (ES6) specificeert Object.assign wat dit zal doen.

Object.assign(obj1, obj2);

Huidige browserondersteuning is beter worden, maar als u zich ontwikkelt voor browsers die geen ondersteuning bieden, kunt u een polyfill.


310



Ik heb op Googled voor code om objecteigenschappen samen te voegen en ben hier terechtgekomen. Maar aangezien er geen code was voor recursieve samenvoeging schreef ik het zelf. (Misschien is jQuery extend recursive BTW?) Hoe dan ook, hopelijk vindt iemand anders het ook nuttig.

(Nu gebruikt de code niet Object.prototype :)

Code

/*
* Recursively merge properties of two objects 
*/
function MergeRecursive(obj1, obj2) {

  for (var p in obj2) {
    try {
      // Property in destination object set; update its value.
      if ( obj2[p].constructor==Object ) {
        obj1[p] = MergeRecursive(obj1[p], obj2[p]);

      } else {
        obj1[p] = obj2[p];

      }

    } catch(e) {
      // Property in destination object not set; create it and set its value.
      obj1[p] = obj2[p];

    }
  }

  return obj1;
}

Een voorbeeld

o1 = {  a : 1,
        b : 2,
        c : {
          ca : 1,
          cb : 2,
          cc : {
            cca : 100,
            ccb : 200 } } };

o2 = {  a : 10,
        c : {
          ca : 10,
          cb : 20, 
          cc : {
            cca : 101,
            ccb : 202 } } };

o3 = MergeRecursive(o1, o2);

Produceert het object o3 like

o3 = {  a : 10,
        b : 2,
        c : {
          ca : 10,
          cb : 20,
          cc : { 
            cca : 101,
            ccb : 202 } } };

226



Let daar op underscore.js's extend-methode doet dit in een one-liner:

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

166



Vergelijkbaar met jQuery extend (), heb je dezelfde functie in angularjs:

// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options  = {validate: true, name: "bar"};
angular.extend(settings, options);

80



Ik moet vandaag objecten samenvoegen, en deze vraag (en antwoorden) hebben me veel geholpen. Ik probeerde een aantal van de antwoorden, maar geen van hen paste in mijn behoeften, dus ik combineerde enkele van de antwoorden, voegde zelf iets toe en bedacht een nieuwe fusiefunctie. Hier is het:

var merge = function() {
    var obj = {},
        i = 0,
        il = arguments.length,
        key;
    for (; i < il; i++) {
        for (key in arguments[i]) {
            if (arguments[i].hasOwnProperty(key)) {
                obj[key] = arguments[i][key];
            }
        }
    }
    return obj;
};

Enkele voorbeelden gebruik:

var t1 = {
    key1: 1,
    key2: "test",
    key3: [5, 2, 76, 21]
};
var t2 = {
    key1: {
        ik1: "hello",
        ik2: "world",
        ik3: 3
    }
};
var t3 = {
    key2: 3,
    key3: {
        t1: 1,
        t2: 2,
        t3: {
            a1: 1,
            a2: 3,
            a4: [21, 3, 42, "asd"]
        }
    }
};

console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));

58



Je kunt gebruiken objectspreidingseigenschappen- momenteel een voorstel van fase 3 ECMAScript.

const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);


43



De gegeven oplossingen moeten worden aangepast om te controleren source.hasOwnProperty(property) in de for..in loops voordat je het toewijst - anders kopieer je de eigenschappen van de hele prototypeketen, wat zelden gewenst is ...


37



Voeg eigenschappen van N-objecten samen in één regel code

Een Object.assign methode maakt deel uit van de ECMAScript 2015 (ES6) -standaard en doet precies wat u nodig hebt. (IE niet ondersteund)

var clone = Object.assign({}, obj);

De methode Object.assign () wordt gebruikt om de waarden van alle opsombare eigen eigenschappen van een of meer bronobjecten naar een doelobject te kopiëren.

Lees verder...

De polyfill om oudere browsers te ondersteunen:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

33