映射整个对象数组,而不会影响所有对象字段

我有一个对象的数组,我需要以某种方式parsing。 这些对象具有一组通用字段和一些不存在于所有对象中的可选字段。 为了这个例子, a,b,c是常见的字段, d,e,f是可选的。 我想对某些领域进行一些操作,例如将ad的值加倍,而把剩下的部分保持原样。 如果某个对象缺less一个或多个可选字段,则应该保留在结果中。

问题是,我想以一种纯粹的function性的方式来做,而不是宣布一个空的数组,并推入它。

示例input:

 const input = [ { a: 3, b: 'test', c: 34, d: 'example' }, { a: 6, b: 'another', c: 0, e: true, f: () => {} } ]; 

预期结果:

 [ { a: 6, b: 'test', c: 34, d: 'EXAMPLE' }, { a: 12, b: 'another', c: 0, e: true, f: () => {} } ] 

我到目前为止所尝试的是使用如下的map

 const result = input.map(x => ({ a: 2 * xa, d: xdtoUppercase() }); 

或者像这样:

 const result = input.map(x => ({ a: 2 * xa, b, c, d: xdtoUppercase(), e, f }); 

但是,这会导致只包含被操纵的字段的对象,或者所有这些对象,而不pipe它们是否存在于原始对象中。

任何build议如何完成?

如果你希望你的对象是不可变的,那么在进行所需的修改之前,你需要创build一个对象的副本。 Object.assign允许你在一个expression式中做到这一点:

 const result = input.map(x => Object.assign({}, x, { a: 2 * xa }, ('d' in x) && { d: xdtoUpperCase() } )); 
 const input = [{ a: 3, b: 'test', c: 34, d: 'example' }, { a: 6, b: 'another', c: 0, e: true, f: () => {} } ]; const result = input.map(x => Object.assign({}, x, { a: 2 * xa }, ('d' in x) && { d: xdtoUpperCase() } )); console.log(result); 
 .as-console-wrapper { min-height: 100%; } 

这个解决scheme需要Babel的Object rest扩展转换插件,因为ECMAScript的Object Rest / Spread Properties仍然处于提议阶段。

创build一个新的对象。 将原始对象分散到新的对象中。 如果您希望更改的属性存在于原始对象中,请将具有新属性值的对象返回到传播。 如果不是,则返回null (spread忽略undefinednull )。 新的值将覆盖旧的。

 const input = [{ a: 3, b: 'test', c: 34, d: 'example' }, { a: 6, b: 'another', c: 0, e: true, f: () => {} } ]; const result = input.map(x => ({ ...x, // spread all props of x ...('a' in x ? { a: 2 * xa } : null), // override a if exists ...('d' in x ? { d: xdtoUpperCase() } : null) // override d if exists })); console.log(result); 

您可以使用map方法,并在每个对象中检查是否存在您想要更改其值的键。 如果是这样,那么你可以相应地改变密钥的价值。

 const input = [ { a: 3, b: 'test', c: 34, d: 'example' }, { a: 6, b: 'another', c: 0, e: true, f: () => {} } ]; const result = input.map(function(obj){ if(obj.a){ obj.a = 2 * obj.a; } if(obj.d){ obj.d = obj.d.toUpperCase() } return obj; }); console.log(result); 

map函数仍然可以使用。在这种情况下,您可以检查对象中是否存在某个键,然后仅对其进行必要的操作。

希望这个片段将是有用的

 const input = [{ a: 3, b: 'test', c: 34, d: 'example' }, { a: 6, b: 'another', c: 0, e: true, f: () => {} } ]; input.map(function(elem, index) { if (elem.hasOwnProperty('a')) { elem.a = elem['a'] * 2; } }) console.log(input) 

在map函数内部,你可以先添加条件来操作input,然后你需要返回修改后的对象。

 const input = [ { a: 3, b: 'test', c: 34, d: 'example' }, { a: 6, b: 'another', c: 0, e: true, f: () => {} } ]; let output = input.map(o => { if(oa) { oa = oa * 2; } if(od) { od = odtoUpperCase(); } return o; }); console.log(output) 

这可能是值得的镜头search。 许多“function性”JavaScript库实现它们以轻松链接您所描述的各种数据修改。

在引擎盖下,他们可能会使用你已经find的相同的Object.assign方法,但是它们允许可读,可重用和易于链接的代码。

一个快速和肮脏的实现来显示语法的变化(es6):

 const propLens = prop => ({ get: obj => obj[prop], // Return a new object with the property set to // a value set: (val, obj) => Object.assign({}, obj, { [prop]: val }), // Return a new object with the property mapped // by a function over: (fn, obj) => Object.assign({}, obj, { [prop]: fn(obj[prop]) }) }); // Helpers to create specific set/over functions const set = (lens, val) => obj => lens.set(val, obj); const over = (lens, fn) => obj => lens.over(fn, obj); // Some utils for the example const { pipe, double, toUpper } = utils(); // Now, you can define your modification by a set // of lens + set/over combinations const convertData = pipe( set( propLens("d"), "added" ), over( propLens("a"), double ), over( propLens("b"), toUpper ) ); // Example data const item = {a: 5, b: "hello", c: "untouched"}; // Converted copy const convertedItem = convertData(item); console.log("Converted:", convertedItem); console.log("item !== convertedItem ->", item !== convertedItem); // Utils function utils() { return { pipe: (...fns) => x => fns.reduce((acc, f) => f(acc), x), double: x => x * 2, toUpper: x => x.toUpperCase() }; }