Object.assign,仅限值

时间:2017-07-28 19:02:14

标签: javascript ecmascript-6

我有两个对象。一个是源对象,另一个是源对象的深层副本。每个中都存在相同的键,但深层副本可能具有与源对象不同的值。例如:

{
  id: 123,
  people: [{
      name: "Bob",
      age: 50
   }, {
      name: "Alice",
      age: 40
  }]
}

and

{
  id: 123,
  people: [{
      name: "Bob",
      age: 51 // bob is older now
   }, {
      name: "Alice",
      age: 40
  }]
}

请注意,对象更深入,有更多的键/对象/数组/值。

我想将更新的副本中的(仅限值)应用回源对象。

重要的是我需要保持源对象的原始参考点。这意味着我无法执行以下任何操作:

sourceObject = updatedCopiedObject;

因为它会覆盖源对象并中断对源对象的引用

Object.assign(sourceObject, updatedCopiedObject);

因为,正如文档所说:

  

目标对象中的属性将被属性覆盖   如果他们有相同的密钥来源。后来的消息来源'属性会   同样地覆盖了之前的那些。

换句话说,它还会覆盖源对象的引用。

我需要做的就是Object.assign会做什么,但不覆盖属性 - 只需更改属性匹配的值

我不知道任何内置方法,它将以必要的递归/深度方式执行此操作。我可以写一个方法,但我想先看看是否已经有解决这个问题的方法。

4 个答案:

答案 0 :(得分:1)

您可以使用Object.entries()迭代对象的属性和值作为数组的键值对。如果值是一个对象,则递归调用相同的函数来重新分配属性值,否则将值设置为源对象属性值



let source = {
  id: 123,
  people: [{
      name: "Bob",
      age: 50
   }, {
      name: "Alice",
      age: 40
  }]
}



let copy = {
  id: 123,
  people: [{
      name: "Bob",
      age: 51 // bob is older now
   }, {
      name: "Alice",
      age: 40
  }]
}

const reassign = (s, c) => {
  for (let [key, prop] of Object.entries(c)) {
    if (typeof prop !== "object") {
      s[key] = prop;
    } else {
      reassign(s[key], prop)
    }
  }
  return [s, c]
}

console.log(reassign(source, copy));




答案 1 :(得分:1)

  

我不知道任何内置方法会以必要的递归/深度方式执行此操作。我可以写一个方法,但我想先看看是否已经有解决这个问题的方法。

不,没有。

答案 2 :(得分:0)

您可以使用迭代和递归方法来分配值。

此提议会迭代源对象并在必要时创建新的目标属性,并在未找到嵌套对象时分配值。

function update(target, source) {
    Object.keys(source).forEach(function(key) {
        if (source[key] && typeof source[key] === 'object') {
            return update(target[key] = target[key] || Array.isArray(source[key]) ? [] : {}, source[key]);
        }
        if (target[key] !== source[key]) {
            target[key] = source[key];
        }
    });
}

var obj1 = { id: 123, people: [{ name: "Bob", age: 50 }, { name: "Alice", age: 40 }] }, obj2 = { id: 123, people: [{ name: "Bob", age: 51 }, { name: "Alice", age: 40 }] };

update(obj1, obj2);
console.log(obj1);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 3 :(得分:0)

guest271314的答案帮助我编写了一个递归解决方案,仅用于分配"值"从一个对象到另一个对象。对于我的应用程序,我需要更改它以处理对象中的数组:

assignObject (target = {}, source) {
  let value = null
  let keys = Object.keys(source)
  for (let key of keys) {
    value = source[key]
    if (typeof value === 'object' && value !== null) {
      if (Object.prototype.toString.call(value) === '[object Array]') {
        target[key] = value
      } else {
        assignObject(target[key], value)
      }
    } else {
      target[key] = value
    }
  }
  return target
}