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.
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" })));
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");
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>
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.
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).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.