One-liner to take some properties from object in ES 6
Solution 1
Here's something slimmer, although it doesn't avoid repeating the list of fields. It uses "parameter destructuring" to avoid the need for the v
parameter.
({id, title}) => ({id, title})
(See a runnable example in this other answer).
@EthanBrown's solution is more general. Here is a more idiomatic version of it which uses Object.assign
, and computed properties (the [p]
part):
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})));
}
If we want to preserve the properties' attributes, such as configurable
and getters and setters, while also omitting non-enumerable properties, then:
function pick(o, ...props) {
var has = p => o.propertyIsEnumerable(p),
get = p => Object.getOwnPropertyDescriptor(o, p);
return Object.defineProperties({},
Object.assign({}, ...props
.filter(prop => has(prop))
.map(prop => ({prop: get(props)})))
);
}
Solution 2
I don't think there's any way to make it much more compact than your answer (or torazburo's), but essentially what you're trying to do is emulate Underscore's pick
operation. It would be easy enough to re-implement that in ES6:
function pick(o, ...fields) {
return fields.reduce((a, x) => {
if(o.hasOwnProperty(x)) a[x] = o[x];
return a;
}, {});
}
Then you have a handy re-usable function:
var stuff = { name: 'Thing', color: 'blue', age: 17 };
var picked = pick(stuff, 'name', 'age');
Solution 3
The trick to solving this as a one-liner is to flip the approach taken: Instead of starting from original object orig
, one can start from the keys they want to extract.
Using Array#reduce
one can then store each needed key on the empty object which is passed in as the initialValue
for said function.
Like so:
const orig = {
id: 123456789,
name: 'test',
description: '…',
url: 'https://…',
};
const filtered = ['id', 'name'].reduce((result, key) => { result[key] = orig[key]; return result; }, {});
console.log(filtered); // Object {id: 123456789, name: "test"}
alternatively...
const filtered = ['id', 'name'].reduce((result, key) => ({
...result,
[key]: orig[key]
}), {});
console.log(filtered); // Object {id: 123456789, name: "test"}
Solution 4
A tiny bit shorter solution using the comma operator:
const pick = (O, ...K) => K.reduce((o, k) => (o[k]=O[k], o), {})
console.log(
pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
)
Solution 5
TC39's object rest/spread properties proposal will make this pretty slick:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
z; // { a: 3, b: 4 }
(It does have the downside of creating the x
and y
variables which you may not need.)
Related videos on Youtube
kirilloid
javascript pirate follow me on @kirilloid_ru for moar pirate JS
Updated on September 23, 2021Comments
-
kirilloid almost 3 years
How one can write a function, which takes only few attributes in most-compact way in ES6?
I've came up with solution using destructuring + simplified object literal, but I don't like that list of fields is repeated in the code.
Is there an even slimmer solution?
(v) => { let { id, title } = v; return { id, title }; }
-
kirilloid almost 10 yearsThanks. This is not an answer for my question, but very nice addition.
-
Ethan Brown almost 10 years(shrug) I feel like it is an answer for your solution; there is no slimmer general solution (torazaburo's solution removes from extra verbage, but the essential problem -- that all property names have to be written twice -- means it doesn't scale any better than your solution). My solution at least scales well...right the
pick
function once, and you can pick as many properties you want and it won't double them. -
Ethan Brown about 9 years+1 nice answer, torazaburo; thanks for making me aware of
Object.assign
; es6 is like a Christmas tree with so many presents under it I'm still finding gifts months after the holiday -
Bergi over 8 yearsWhy do you use
hasOwnProperty
? If the fields are hand-selected, evenin
seems to be more appropriate; although I'd go for omitting the check completely and just let them default toundefined
. -
Ethan Brown over 8 yearsBergi, it's a reasonable point...I just consider properties (not methods) on a prototype chain to be weird and "smelly" (as in they are a code smell), and I prefer to filter them out by default. If there's an application that needs prototype properties, well...there can be an option for that.
-
kirilloid about 7 yearsThis is a convenient form of
omit
, but notpick
-
Alexandr Priezzhev about 7 yearsWhat is the reason for downvote? Doesn't it work for you?
-
Rizwan Patel almost 7 yearswhat about json arrays !
-
Endless over 6 yearsGot an error: Property description must be an object: undefined. Shouldn't it be
filter(...).map(prop => ({[prop]: get(prop)})))
? -
Tomas M over 6 yearshow to use this? Can you provide an example?
-
shesek over 6 yearsIt works just like the other
pick
functions in this thread:pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
-
Patrick Roberts over 6 yearsFor your first
pick()
implementation you could also do something likereturn props.reduce((r, prop) => (r[prop] = o[prop], r), {})
-
duhseekoh over 6 yearsunfortunately that version of pick won't be type safe in flow or typescript. if you want type safety, there's no way around destructure assignment of original object, then assigning each into a new object.
-
gfullam over 5 yearsI would love to see a variant that does the exact opposite of this as an ES proposal:
let { a, b } as z = { x: 1, y: 2, a: 3, b: 4 }
-
x-yuri over 5 yearsWhen a property doesn't exist in an object, you get
undefined
. Sometimes it matters. Other than that, nice idea. -
x-yuri over 5 years
lodash
doesn't have this peculiarity. I think I'll go with it. -
Remzes about 5 years(index):36 Uncaught SyntaxError: Invalid destructuring assignment target
-
Saksham about 5 years@Remzes dont know where and how you are executing this but it works well in SO code editor and in chrome developer tools.
-
Remzes about 5 yearsI used jsfiddle
-
Dan Dascalescu about 5 yearsI've improved your answer a bit, but it's still too verbose, vs. what the OP asked for. It repeats not just the field names, but also the new object's name.
-
Guy Gascoigne-Piggford almost 4 yearsFYI a typescript variant of this is: export function pick<T, D extends keyof T>(o: T, ...props: D[]) { return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]}))); }
-
Shah almost 3 yearsIs it going to handle Array in the object as well?