Reputation: 4211
I have some code that essentially takes an array of objects and just adds an additional key to each item. I want to be able to express this as tersely as possible as an experiment.
let fruits = [
{"type" : "orange"},
{"type" : "apple"},
{"type" : "banana"}
];
console.log(fruits.map((fruit) => {
fruit.price = "$1.00";
return fruit;
}));
Currently, this works, but it's certainly no one liner and the return
statement is still in there, and I feel like there's a way to get rid of it given the fat arrow syntax.
Upvotes: 0
Views: 174
Reputation: 78525
One approach would be to use Object.assign to extend the object and also return the resulting newly-created object:
console.log(fruits.map(fruit => Object.assign(fruit, { price: "1.00" })));
This removes the need for the return
keyword, but it's hardly the biggest space-saver. It is also equivalent to what you already have (in that the original fruit
object is modified. As joews points out below, if you wanted to leave the original array in-tact you can use an empty target object like so:
Object.assign({}, fruit, { price: "1.00"});
This will ensure that your original array is unmodified (which may or may not be what you want).
Finally, combining this with the spread operator gives us:
console.log(fruits.map(fruit => ({...fruit, price: "1.00" })));
Upvotes: 3
Reputation: 664415
A mapping function should almost always be pure. If you are only going to modify the objects, a simple loop will do better (for (let fruit of fruits) fruit.price = …; console.log(fruits);
).
So when you're returning a new object, a one-liner will be easy:
console.log(fruits.map(({type}) => ({type, price:"$1.00"})));
If you've got many properties, or properties you don't know, then Object.assign({}, …)
is your friend (as in @joews' comment to @RGraham's answer).
Upvotes: 0
Reputation: 159895
There are many ways to do this:
If you want to do it inline you can use the comma operator (though it's a little obscure):
fruits.map((fruit) => (fruit.price = "$1.00", fruit))
We could also use &&
since assignment returns the assigned value and "$1.00"
is truthy but the comma operator is more general, since we can also set false
or 0
and have everything continue to work.
It's probably better to make a helper function, however:
// 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;
}
}
Then you can use:
fruits.map(setter("price")("$1.00"))
As @Suppen points out in their comment, because normal JavaScript objects are mutable you can also avoid the map
and use forEach
instead:
fruits.forEach(fruit => fruit.price = "$1.00");
// Each element in fruits has been modified in-place.
Upvotes: 2
Reputation: 173
Could do something like this, not recommended for readibility but technically one line.
fruits.map(fruit => (fruit.price = "$1.00") && fruit);
As others have mentioned this method just adds a property to the object and does not copy it. A simple way to keep this as a one liner, use a map and actually create a copy would be:
fruits.map(fruit => Object.assign({price: "$1.00"}, fruit));
Object.assign()
will assign all the properties of fruit
to the object { price: "$1.00" }
and return it.
Live example:
"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>
Upvotes: 2
Reputation: 21881
You can also use .forEach()
instead of .map()
to directly modify fruits
if you don't need the original version of fruits
fruits.forEach((fruit) => fruit.price = "$1.00");
http://www.es6fiddle.net/igwdk0gk/
Upvotes: 3