写一个.map调用更优雅的方式?

时间:2015-11-12 15:02:25

标签: javascript functional-programming ecmascript-6

我有一些代码基本上需要一个对象数组,只是为每个项添加一个额外的键。我希望能够尽可能简洁地表达这一点作为实验。

{
  "size": 0,
  "aggs": {
    "unique_ids": {
      "terms": {
        "field": "campaign_id",
        "size": 10
      },
      "aggs": {
        "one_value": {
          "max": {
            "field": "clicks"
          }
        }
      }
    },
    "sum_uniques": {
      "sum_bucket": {
        "buckets_path": "unique_ids>one_value"
      }
    }
  }
}

目前,这是有效的,但它当然没有任何一个班轮,let fruits = [ {"type" : "orange"}, {"type" : "apple"}, {"type" : "banana"} ]; console.log(fruits.map((fruit) => { fruit.price = "$1.00"; return fruit; })); 声明仍在那里,我觉得有一种方法可以摆脱它,因为胖箭语法。

5 个答案:

答案 0 :(得分:3)

一种方法是使用Object.assign扩展对象并返回生成的新对象:

console.log(fruits.map(fruit => Object.assign(fruit, { price: "1.00" })));

Babel REPL Example

这消除了对return关键字的需求,但它并不是最大的节省空间。它也等同于你已经拥有的东西(因为原来的fruit对象被修改了。正如joews指出的那样,如果你想保留原始数组,你可以使用一个空的目标对象,如下所示:

Object.assign({}, fruit, { price: "1.00"});

这将确保您的原始数组未经修改(可能是您想要的也可能不是。)

答案 1 :(得分:3)

如果您不需要.forEach()

的原始版本,也可以使用.map()代替fruits直接修改fruits
fruits.forEach((fruit) => fruit.price = "$1.00");

http://www.es6fiddle.net/igwdk0gk/

答案 2 :(得分:2)

可以做这样的事情,不推荐用于可读性,但技术上是一行。

fruits.map(fruit => (fruit.price = "$1.00") && fruit);

正如其他人提到的那样,这个方法只是为对象添加一个属性而不复制它。将此作为一个简单的方法,使用地图并实际创建副本的简单方法是:

fruits.map(fruit => Object.assign({price: "$1.00"}, fruit));

Object.assign()会将fruit的所有属性分配给对象{ price: "$1.00" }并将其返回。

实例:



"use strict";

let log = function() {
  output.textContent += [].join.call(arguments, ' ') + '\n\n';
};

log('# MAP (OR FOREACH) WITHOUT ASSIGN');

let fruits = [
   {"type" : "orange"},
   {"type" : "apple"},
   {"type" : "banana"}
];
let newfruits = fruits.map(fruit => (fruit.price = "$1.00") && fruit);

log('fruits', JSON.stringify(fruits));
log('newfruits', JSON.stringify(newfruits));
log('^-- Both are modified since newfruits its a new array with the same objects');

log('# MAP WITH ASSIGN');

fruits = [
   {"type" : "orange"},
   {"type" : "apple"},
   {"type" : "banana"}
];
newfruits = fruits.map(fruit => Object.assign({price: "$1.00"}, fruit));

log('fruits', JSON.stringify(fruits));
log('newfruits', JSON.stringify(newfruits));
log('^-- Only newfruits is modified since its a new array with new objects');

pre {
  word-wrap: break-word;
}

<pre id="output"></pre>
&#13;
&#13;
&#13;

答案 3 :(得分:1)

有很多方法可以做到这一点:

使用逗号运算符

的副作用

如果你想内联你可以使用逗号运算符(虽然它有点模糊):

fruits.map((fruit) => (fruit.price = "$1.00", fruit))

我们也可以使用&&,因为赋值会返回指定的值,"$1.00"是真实的,但逗号运算符更通用,因为我们也可以设置false0让一切继续发挥作用。

高阶函数

然而,制作辅助函数可能更好:

// We're currying manually here, but you could also make the signature
// setter(name, value) and use your function of choice to curry when you need to.
function setter(name) {
  return (value) => (obj) => {
    obj[name] = value;
    return obj;
  }
}

然后你可以使用:

fruits.map(setter("price")("$1.00"))

拥抱可变性

正如@Suppen在评论中指出的那样,因为普通的JavaScript对象是可变的,所以您也可以避免使用map并使用forEach代替:

fruits.forEach(fruit => fruit.price = "$1.00");
// Each element in fruits has been modified in-place.

答案 4 :(得分:0)

映射函数几乎总是纯粹的。如果您只想修改对象,一个简单的循环会做得更好(for (let fruit of fruits) fruit.price = …; console.log(fruits);)。

因此,当您返回一个新对象时,单行会很容易:

console.log(fruits.map(({type}) => ({type, price:"$1.00"})));

如果你有很多属性或属性你不知道,那么Object.assign({}, …)就是你的朋友(就像@ joews&#39;评论@RGraham&#39的答案)

相关问题