1

对于我当前的项目,我正在使用一个返回如下格式数据的 API:

{
  groups: [
    {
      items: [
        {
          points: [
            { name: "name1", ... },
            { name: "name2", ... },
            { name: "name3", ... },
            ...
          ],
          ...
        },
        ...
      ]
    },
    ...
  ],
  ...
};

我想创建一个纯函数, mapValues,它接受一个上述格式的对象,以及一个将每个对象映射name到 a的对象value,并返回相同的结构,但每个都point包含value对应于它的name.

例如,调用mapValues(data, { name1: "value1", name2: "value2", name3: "value3" })应该返回:

{
  groups: [
    {
      items: [
        {
          points: [
            { name: "name1", value: "value1", ... },
            { name: "name2", value: "value2", ... },
            { name: "name3", value: "value3", ... },
            ...
          ],
          ...
        },
        ...
      ]
    },
    ...
  ],
  ...
};

这是我的第一关:

function mapValues(data, values) {
  return _.extend({}, data, {
    groups: _.map(ui.groups, (group) => {
      return _.extend({}, group, {
        items: _.map(group.items, (item) => {
          return _.extend({}, item, {
            points: _.map(item.points, (point) => {
              return _.extend({ value: values[point.name] }, point);
            })
          });
        })
      });
    })
  });
}

这行得通,但是有相当多的嵌套重复代码。对于我的第二次尝试,我达到了递归。

function mapValues(data, values) {
  return (function recursiveMap(object, attributes) {
    if (attributes.length === 0) { return _.extend({ value: values[object.name] }, object); }
    let key = attributes[0];
    return _.extend({}, object, {
      [key]: _.map(object[key], child => recursiveMap(child, attributes.slice(1)))
    });
  })(ui, ["groups", "items", "points"]);
}

这也有效,但它很难阅读而且不是很简洁。

有没有更简洁的方法来使用 Lodash 递归地映射对象?理想情况下,我正在寻找一种功能性方法。

4

2 回答 2

1

这是您可以使用的一种方法Object.assign,没有花哨的功能

var data = <your data here>;
var values = <your mapped values>;

data.groups.items.points.map(p=>
  Object.assign(p, {value: values[p.name]})
);

这是有效的,因为数组和对象是通过引用传递的。因此,对值的任何修改都会导致原始值被更改。

如果您不想改变原始数据集,则需要您将其{}用作第一个参数(分配给新的空对象)并为每个对象显示清晰的读/写路径。

var newData = Object.assign({}, data,
  {groups:
    {items:
      {points: data.groups.items.points.map(p=>
        Object.assign({}, p, {value: values[p.name]})
      )}
    }
  }
);
于 2016-05-10T14:20:54.183 回答
0

我知道你想要 Lodash,但前段时间我遇到了同样的问题,我想出了这个JSFiddle,我正在使用由nervgh创建的很棒的工具。它非常简单但很有用。您可以将此功能调整为纯使用Object.assign,接受关键参数并根据需要进行调整。你明白了。

function mapValues(data, values) {
  var iterator = new RecursiveIterator(data);
  for(let {node} of iterator) {
    if(node.hasOwnProperty('name')) {
        node.value = values[node.name];
    }
  }
  return data;
}
于 2016-05-10T05:57:03.350 回答