One-liner to take some properties from object in ES 6

68,930

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.)

Share:
68,930

Related videos on Youtube

kirilloid
Author by

kirilloid

javascript pirate follow me on @kirilloid_ru for moar pirate JS

Updated on September 23, 2021

Comments

  • kirilloid
    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
    kirilloid almost 10 years
    Thanks. This is not an answer for my question, but very nice addition.
  • Ethan Brown
    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
    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
    Bergi over 8 years
    Why do you use hasOwnProperty? If the fields are hand-selected, even in seems to be more appropriate; although I'd go for omitting the check completely and just let them default to undefined.
  • Ethan Brown
    Ethan Brown over 8 years
    Bergi, 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
    kirilloid about 7 years
    This is a convenient form of omit, but not pick
  • Alexandr Priezzhev
    Alexandr Priezzhev about 7 years
    What is the reason for downvote? Doesn't it work for you?
  • Rizwan Patel
    Rizwan Patel almost 7 years
    what about json arrays !
  • Endless
    Endless over 6 years
    Got an error: Property description must be an object: undefined. Shouldn't it be filter(...).map(prop => ({[prop]: get(prop)})))?
  • Tomas M
    Tomas M over 6 years
    how to use this? Can you provide an example?
  • shesek
    shesek over 6 years
    It works just like the other pick functions in this thread: pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
  • Patrick Roberts
    Patrick Roberts over 6 years
    For your first pick() implementation you could also do something like return props.reduce((r, prop) => (r[prop] = o[prop], r), {})
  • duhseekoh
    duhseekoh over 6 years
    unfortunately 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
    gfullam over 5 years
    I 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
    x-yuri over 5 years
    When a property doesn't exist in an object, you get undefined. Sometimes it matters. Other than that, nice idea.
  • x-yuri
    x-yuri over 5 years
    lodash doesn't have this peculiarity. I think I'll go with it.
  • Remzes
    Remzes about 5 years
    (index):36 Uncaught SyntaxError: Invalid destructuring assignment target
  • Saksham
    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
    Remzes about 5 years
    I used jsfiddle
  • Dan Dascalescu
    Dan Dascalescu about 5 years
    I'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
    Guy Gascoigne-Piggford almost 4 years
    FYI 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
    Shah almost 3 years
    Is it going to handle Array in the object as well?