javascript - 更新 Javascript 对象、嵌套数据 - 仅在不可更新时插入

标签 javascript arrays object insert lodash

假设我有以下数据

var obj = {
  test: 'somedata',
  scores: [
    {
      "points":99, 
      "id":"x12"
    },
    {
      "points":21, 
      "id":"x13"
    }
  ],
  sites: [
    {
      "exercises":21, 
      "sid":"s12"
    },
    {
      "exercises":23, 
      "sid":"s11"
    }
  ],
  history: {
    key: 'value',
    commits: [
      {
         id: 1,
         value: 'thank you'
      }
    ]
  }
}

请注意scoressites包含基于 id 且具有唯一元素的数组在scores并基于sidsites 。我想要一个具有以下魔力的函数:

//will **update** obj.test to 'newdata' and return {test:'newdata'}
magicUpdate(obj, {test:'newdata'}) 

//will **insert** obj.newkey with with value 'value' and return {newkey: 'value'}
magicUpdate(obj, {newkey: 'value'})

//will do nothing and return {}
magicUpdate(obj, {scores: []})

//will **update** scores[0] and return {scores:[{points:3, id: "x12"}]}, as id "x12" is already in the array at index 0
magicUpdate(obj, {scores:[{points:3, id: "x12"}])

//will **insert** {points:3, id: "x14"} into obj.scores and return {scores:[{points:3, id: "x14"}]}
magicUpdate(obj, {scores:[{points:3, id: "x14"}]})

//will **update** sites[0] and return {sites:[{exercises:22, sid: "s12"}]}, as id "s12" is already in the array at index 0
magicUpdate(obj, {sites:[{exercises:22, sid: "s12"}])

//will **insert** {exercises:10, sid: "s14"} into obj.sites and return {sites:[{exercises:10, sid: "s14"}]}
magicUpdate(obj, {sites:[{exercises:10, sid: "s14"}]})

//and also be recursive ...
//will **update** obj.history.commits[0]
magicUpdate(obj, {'history.commits': [{id:1, value: 'changed'}]});

我见过.update 进行递归,但前提是传递 path这应该是自动确定的。然后是 .merge其内部使用 _.baseMerge尽管我不理解该函数的签名,但它非常接近我所需要的。

_.merge(
{scores:[{id: 12, points:10}, {id: 13, points:10}]}, 
{scores:[{id: 14, points:10}, {id: 15, points:10}]}
) 
// returns {scores:[{id: 14, points:10}, {id: 15, points:10}]} not the fully merged array

有人能给我指出一个好的方向或者用 lodash 实现了类似的事情吗?

最佳答案

您在帖子中提到的 magicUpdate 函数确实可以使用 lodash 函数来实现。

对于这个实现,我主要使用了 _ .get_ .set_ .unionWith ,尽管我确信它可以使用其他一些来实现:

// src will be mutated. For simplicity's sake, obj is an object with only one property that represents the changes to make to src
function magicUpdate(src, obj) {
  var key = _.first(_.keys(obj)),
    value = _.get(obj, key),
    srcValue = _.get(src, key),
    comparator = function(a, b) {
      var idKey = _.isUndefined(a.id) ? 'sid' : 'id';
      return a[idKey] === b[idKey];
    }

  if (_.isArray(srcValue)) {
    value = _.unionWith(value, srcValue, comparator);
  }

  return _.set(src, key, value);
}

正如您可能已经注意到查看代码一样,返回类型是变异对象,而不是您所要求的类型。我不太确定您想要什么返回值。

无论如何,Lodash 没有内置的对象差异函数,因此有必要开发类似的东西,以防万一你想要旧对象和修改后的对象之间的差异(你还必须 _ .clone对象首先要有一个副本并能够进行比较)。

我提出的函数的想法是尝试获取 obj 的键(这是我们要在 src 中修改的键)并检查它是否存在并且是一个数组。如果是这样,我们只需添加两个数组,并更新 src 中与 obj 中具有相同 id 的数组。由于 sitesscoreshistoryidsid 我必须向 _.unionWith 函数的比较器添加更多逻辑。

如果key不存在或者不是数组,我们只需在src中设置它。

如果您想使用它,这里有 fiddle。希望对您有所帮助。

更新

我的第一个解决方案旨在一次更新一个属性。不过,似乎可以同时更新多个。

一种快速解决方案可能是使用更新迭代对象并一次更新一个属性。

function updateProperty(src, obj) {
  var key = _.first(_.keys(obj)),
    value = _.get(obj, key),
    srcValue = _.get(src, key),
    comparator = function(a, b) {
      var idKey = _.isUndefined(a.id) ? 'sid' : 'id';
      return a[idKey] === b[idKey];
    }

  if (_.isArray(srcValue)) {
    value = _.unionWith(value, srcValue, comparator);
  }

  return _.set(src, key, value);
}

function magicUpdate(obj, src) {
  _.forEach(src, function(value, key) {
      updateProperty(obj, _.pick(src, key));
  });
  return obj;
}

Fiddle

关于javascript - 更新 Javascript 对象、嵌套数据 - 仅在不可更新时插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40041787/

相关文章:

javascript - 用一组重量平衡秤

javascript - JS 数学方法问题 : function is removing multiple min/max values (I think? )

java - Android Arraylist 查找索引

javascript - javascript/css/html中的 war 卡牌游戏

javascript - 使用按键vanilla javascript动态移动div

php - 解析错误: syntax error, unexpected T_VARIABLE in Xro_config.php on line 21

javascript - 从 javascript 对象获取项目

javascript - Vue.js 将对象添加到现有数组

javascript - 如何捕捉 `WebSocket connection to ' ws ://xxx:nn' failed: Connection closed before receiving a handshake response` error?

javascript - jQuery 访问 JSON 对象?