【问题标题】:Object.assign, values onlyObject.assign,仅值
【发布时间】:2018-01-04 22:42:03
【问题描述】:

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

{
  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
  }]
}

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

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

重要的是我需要维护源对象的原始参考点。这意味着我不能执行以下任何操作:

sourceObject = updatedCopiedObject;

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

Object.assign(sourceObject, updatedCopiedObject);

因为,正如文档所说:

目标对象中的属性将被 如果它们具有相同的密钥,则来源。稍后来源的属性将 类似地覆盖之前的。

换句话说,它也覆盖了源对象的引用。

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

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

【问题讨论】:

  • 所以你的问题是,是否有一个内置的方法可以满足你的需求?不,没有。
  • 是的 - 谢谢。我想知道的。
  • @torazaburo 您是否考虑过在答案中发表您的评论?

标签: javascript ecmascript-6


【解决方案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));

【讨论】:

  • 感谢您的回复。像这样的东西是我最后的手段,因为真实的物体巨大而复杂。希望有一个类似于 Object.assign 的内置方法。
  • @oooyaya Object.entries() 是一个内置方法。您也可以使用 JSON.stringify()JSON.parse() replacer 函数。您仍然需要递归迭代所有作为对象的属性值。
  • 是的,但它用于递归方法。 Object.keys 或 for...in 也是如此,但使用其中任何一个都有助于遍历对象以手动复制它。解决问题的作用不大。
  • “是的,但它用于递归方法。” 是的,这是问题的要求,因为预期结果是迭代 JavaScript 对象的所有属性和值;保存以使用 JSON.stringify()String.prototype.replace() 将 JavaScript 对象转换为字符串以更改值。 “Object.keys 或 for...in 也是如此,但使用其中任何一个都有助于遍历对象以手动复制它。它并没有真正解决问题。” 是的,预期的结果从函数返回原始问题中描述的。您试图解决什么“问题”?
  • "我不知道有任何内置方法可以以必要的递归/深度方式执行此操作。我可以编写一个方法,但我想看看是否有已经先解决了这个问题。"
【解决方案2】:

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

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

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】:

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

    不,没有。

    【讨论】:

      【解决方案4】:

      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
      }
      

      【讨论】:

        猜你喜欢
        • 2021-10-01
        • 2019-10-19
        • 1970-01-01
        • 2021-09-09
        • 1970-01-01
        • 2019-08-22
        • 2018-08-29
        • 2016-07-18
        • 2012-07-25
        相关资源
        最近更新 更多