How can I merge javascript two objects but only up

2019-07-08 18:56发布

问题:

I'm trying to write a function that will let me update my kitchen in this example below. Using something like underscore's extend, however, blows away the beer in my fridge as it's updating the entire fridge object.

Is there a simple method I can use so that I only make updates with the properties that change in my changeKitchen object and not update the entire fridge object?

// My original kitchen
var kitchen = {
  fridge: {
    beer: true,
    celery: false
  },
  cabinets: {
    candy: true
  }
};


// updates I would like to make to my kitchen
var changeKitchen = {
  fridge: {
    celery: true
  }
};


var updatedKitchen = _.extend(kitchen, changeKitchen);

console.log(updatedKitchen);

Returns

var kitchen = {
  fridge: {
    celery: false // beer is gone
  },
  cabinets: {
    candy: true
  }
};

However I would like to have:

var kitchen = {
  fridge: {
    beer: true,
    celery: true // changed
  },
  cabinets: {
    candy: true
  }
};

回答1:

Since you're already using Underscore, you could use Lodash instead, which is a superset of Underscore, and use its #merge function.

See this question about Differences between Lodash and underscore

// My original kitchen
var kitchen = {
  fridge: {
    beer: true,
    celery: false
  },
  cabinets: {
    candy: true
  }
};


// updates I would like to make to my kitchen
var changeKitchen = {
  fridge: {
    celery: true
  }
};


var updatedKitchen = _.merge(kitchen, changeKitchen);

document.write(JSON.stringify(updatedKitchen));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>



回答2:

Use _.extend on the nested objects instead:

function update(obj1, obj2) {
  for (var p in obj2) {
    if (obj1[p]) {
        _.extend(obj1[p], obj2[p]);
    } else {
      obj1[p] = obj2[p];
    }
  }
}

update(kitchen, changeKitchen);

DEMO



回答3:

Here is a solution in plain Javascript:

var kitchen = { fridge: { beer: true, celery: false }, cabinets: { candy: true } },
    changeKitchen = { fridge: { celery: true } };

function update(source, target) {
    Object.keys(target).forEach(function (k) {
        if (typeof target[k] === 'object') {
            source[k] = source[k] || {};
            update(source[k], target[k]);
        } else {
            source[k] = target[k];
        }
    });
}

update(kitchen, changeKitchen);
document.write('<pre>' + JSON.stringify(kitchen, 0, 4) + '</pre>');



回答4:

Try using for..in loop , Object.keys()

// My original kitchen
var kitchen = {
  fridge: {
    beer: true,
    celery: false
  },
  cabinets: {
    candy: true
  }
};

var changeKitchen = {
  fridge: {
    celery: true
  }
};

for (var prop in changeKitchen) {
  if (kitchen[prop]) {
    kitchen[prop]
      [Object.keys(changeKitchen[prop])] = changeKitchen[prop]
         [Object.keys(changeKitchen[prop])]
  }
}

console.log(kitchen)