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 };
}
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)})))
);
}
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');
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"}
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')
)
ES6 was the latest spec at the time when the question was written. As explained in this answer, key picking is significantly shorter in ES2019 than in ES6:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
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.)
You can use object destructuring to unpack properties from the existing object and assign them to variables with different names - fields of a new, initially empty object.
const person = {
fname: 'tom',
lname: 'jerry',
aage: 100,
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
There's currently a strawman proposal for improving JavaScript's object shorthand syntax, which would enable "picking" of named properties without repetition:
const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});
console.log(picked);
// {id: "68646", title: "Scarface"}
Unfortunately, the proposal doesn't seem to be going anywhere any time soon. Last edited in July 2017 and still a draft at Stage 0, suggesting the author may have ditched or forgotten about it.
ES5 and earlier (non-strict mode)
The concisest possible shorthand I can think of involves an ancient language feature nobody uses anymore:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
with statements are forbidden in strict mode, making this approach useless for 99.999% of modern JavaScript. Bit of a shame, because this is the only halfway-decent use I've found for the with feature. 😀
I have similar to Ethan Brown's solution, but even shorter - pick function. Another function pick2 is a bit longer (and slower), but allows to rename properties in the similar to ES6 manner.
const pick = (o, ...props) => props.reduce((r, p) => p in o ? {...r, [p]: o[p]} : r, {})
const pick2 = (o, ...props) => props.reduce((r, expr) => {
const [p, np] = expr.split(":").map( e => e.trim() )
return p in o ? {...r, [np || p]: o[p]} : r
}, {})
Here is the usage example:
const d = { a: "1", c: "2" }
console.log(pick(d, "a", "b", "c")) // -> { a: "1", c: "2" }
console.log(pick2(d, "a: x", "b: y", "c")) // -> { x: "1", c: "2" }
I required this sollution but I didn't knew if the proposed keys were available. So, I took #torazaburo answer and improved for my use case:
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => {
if (o[prop]) return {[prop]: o[prop]};
}));
}
// Example:
var person = { name: 'John', age: 29 };
var myObj = pick(person, 'name', 'sex'); // { name: 'John' }
Some great solutions above, didn't see one for Typescript fleshed out, so here it goes. Based on #Ethan Browns solution above
const pick = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Pick< T, K > =>
keys.reduce< any >( ( r, key ) => {
r[ key ] = obj[ key ];
return r;
}, {} );
And for bonus, here is TS friendly es6 omit, and one that is much more performant below, but less es6.
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > =>
keys.reduce( ( r, key ) => ( delete r[ key ], r ), {
...obj,
} );
Way more performant omit: http://jsben.ch/g6QCK
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > => {
let r: any = {};
let length = keys.length;
while ( length-- ) {
const key = keys[ length ];
r[ key ] = obj[ key ];
}
return r;
};
inspired by the reduce approach of https://stackoverflow.com/users/865693/shesek:
const pick = (orig, keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})
or even slightly shorter using the comma operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator)
const pick = (obj, keys) => keys.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
usage:
pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear')
results in:
{model: "F40", productionYear: 1987}
Related
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 };
}
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)})))
);
}
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');
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"}
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')
)
ES6 was the latest spec at the time when the question was written. As explained in this answer, key picking is significantly shorter in ES2019 than in ES6:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
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.)
You can use object destructuring to unpack properties from the existing object and assign them to variables with different names - fields of a new, initially empty object.
const person = {
fname: 'tom',
lname: 'jerry',
aage: 100,
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
There's currently a strawman proposal for improving JavaScript's object shorthand syntax, which would enable "picking" of named properties without repetition:
const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});
console.log(picked);
// {id: "68646", title: "Scarface"}
Unfortunately, the proposal doesn't seem to be going anywhere any time soon. Last edited in July 2017 and still a draft at Stage 0, suggesting the author may have ditched or forgotten about it.
ES5 and earlier (non-strict mode)
The concisest possible shorthand I can think of involves an ancient language feature nobody uses anymore:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
with statements are forbidden in strict mode, making this approach useless for 99.999% of modern JavaScript. Bit of a shame, because this is the only halfway-decent use I've found for the with feature. 😀
I have similar to Ethan Brown's solution, but even shorter - pick function. Another function pick2 is a bit longer (and slower), but allows to rename properties in the similar to ES6 manner.
const pick = (o, ...props) => props.reduce((r, p) => p in o ? {...r, [p]: o[p]} : r, {})
const pick2 = (o, ...props) => props.reduce((r, expr) => {
const [p, np] = expr.split(":").map( e => e.trim() )
return p in o ? {...r, [np || p]: o[p]} : r
}, {})
Here is the usage example:
const d = { a: "1", c: "2" }
console.log(pick(d, "a", "b", "c")) // -> { a: "1", c: "2" }
console.log(pick2(d, "a: x", "b: y", "c")) // -> { x: "1", c: "2" }
I required this sollution but I didn't knew if the proposed keys were available. So, I took #torazaburo answer and improved for my use case:
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => {
if (o[prop]) return {[prop]: o[prop]};
}));
}
// Example:
var person = { name: 'John', age: 29 };
var myObj = pick(person, 'name', 'sex'); // { name: 'John' }
Some great solutions above, didn't see one for Typescript fleshed out, so here it goes. Based on #Ethan Browns solution above
const pick = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Pick< T, K > =>
keys.reduce< any >( ( r, key ) => {
r[ key ] = obj[ key ];
return r;
}, {} );
And for bonus, here is TS friendly es6 omit, and one that is much more performant below, but less es6.
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > =>
keys.reduce( ( r, key ) => ( delete r[ key ], r ), {
...obj,
} );
Way more performant omit: http://jsben.ch/g6QCK
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > => {
let r: any = {};
let length = keys.length;
while ( length-- ) {
const key = keys[ length ];
r[ key ] = obj[ key ];
}
return r;
};
inspired by the reduce approach of https://stackoverflow.com/users/865693/shesek:
const pick = (orig, keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})
or even slightly shorter using the comma operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator)
const pick = (obj, keys) => keys.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
usage:
pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear')
results in:
{model: "F40", productionYear: 1987}
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 };
}
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)})))
);
}
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');
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"}
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')
)
ES6 was the latest spec at the time when the question was written. As explained in this answer, key picking is significantly shorter in ES2019 than in ES6:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
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.)
You can use object destructuring to unpack properties from the existing object and assign them to variables with different names - fields of a new, initially empty object.
const person = {
fname: 'tom',
lname: 'jerry',
aage: 100,
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
There's currently a strawman proposal for improving JavaScript's object shorthand syntax, which would enable "picking" of named properties without repetition:
const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});
console.log(picked);
// {id: "68646", title: "Scarface"}
Unfortunately, the proposal doesn't seem to be going anywhere any time soon. Last edited in July 2017 and still a draft at Stage 0, suggesting the author may have ditched or forgotten about it.
ES5 and earlier (non-strict mode)
The concisest possible shorthand I can think of involves an ancient language feature nobody uses anymore:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
with statements are forbidden in strict mode, making this approach useless for 99.999% of modern JavaScript. Bit of a shame, because this is the only halfway-decent use I've found for the with feature. 😀
I have similar to Ethan Brown's solution, but even shorter - pick function. Another function pick2 is a bit longer (and slower), but allows to rename properties in the similar to ES6 manner.
const pick = (o, ...props) => props.reduce((r, p) => p in o ? {...r, [p]: o[p]} : r, {})
const pick2 = (o, ...props) => props.reduce((r, expr) => {
const [p, np] = expr.split(":").map( e => e.trim() )
return p in o ? {...r, [np || p]: o[p]} : r
}, {})
Here is the usage example:
const d = { a: "1", c: "2" }
console.log(pick(d, "a", "b", "c")) // -> { a: "1", c: "2" }
console.log(pick2(d, "a: x", "b: y", "c")) // -> { x: "1", c: "2" }
I required this sollution but I didn't knew if the proposed keys were available. So, I took #torazaburo answer and improved for my use case:
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => {
if (o[prop]) return {[prop]: o[prop]};
}));
}
// Example:
var person = { name: 'John', age: 29 };
var myObj = pick(person, 'name', 'sex'); // { name: 'John' }
Some great solutions above, didn't see one for Typescript fleshed out, so here it goes. Based on #Ethan Browns solution above
const pick = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Pick< T, K > =>
keys.reduce< any >( ( r, key ) => {
r[ key ] = obj[ key ];
return r;
}, {} );
And for bonus, here is TS friendly es6 omit, and one that is much more performant below, but less es6.
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > =>
keys.reduce( ( r, key ) => ( delete r[ key ], r ), {
...obj,
} );
Way more performant omit: http://jsben.ch/g6QCK
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > => {
let r: any = {};
let length = keys.length;
while ( length-- ) {
const key = keys[ length ];
r[ key ] = obj[ key ];
}
return r;
};
inspired by the reduce approach of https://stackoverflow.com/users/865693/shesek:
const pick = (orig, keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})
or even slightly shorter using the comma operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator)
const pick = (obj, keys) => keys.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
usage:
pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear')
results in:
{model: "F40", productionYear: 1987}
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 };
}
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)})))
);
}
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');
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"}
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')
)
ES6 was the latest spec at the time when the question was written. As explained in this answer, key picking is significantly shorter in ES2019 than in ES6:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
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.)
You can use object destructuring to unpack properties from the existing object and assign them to variables with different names - fields of a new, initially empty object.
const person = {
fname: 'tom',
lname: 'jerry',
aage: 100,
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
There's currently a strawman proposal for improving JavaScript's object shorthand syntax, which would enable "picking" of named properties without repetition:
const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});
console.log(picked);
// {id: "68646", title: "Scarface"}
Unfortunately, the proposal doesn't seem to be going anywhere any time soon. Last edited in July 2017 and still a draft at Stage 0, suggesting the author may have ditched or forgotten about it.
ES5 and earlier (non-strict mode)
The concisest possible shorthand I can think of involves an ancient language feature nobody uses anymore:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
with statements are forbidden in strict mode, making this approach useless for 99.999% of modern JavaScript. Bit of a shame, because this is the only halfway-decent use I've found for the with feature. 😀
I have similar to Ethan Brown's solution, but even shorter - pick function. Another function pick2 is a bit longer (and slower), but allows to rename properties in the similar to ES6 manner.
const pick = (o, ...props) => props.reduce((r, p) => p in o ? {...r, [p]: o[p]} : r, {})
const pick2 = (o, ...props) => props.reduce((r, expr) => {
const [p, np] = expr.split(":").map( e => e.trim() )
return p in o ? {...r, [np || p]: o[p]} : r
}, {})
Here is the usage example:
const d = { a: "1", c: "2" }
console.log(pick(d, "a", "b", "c")) // -> { a: "1", c: "2" }
console.log(pick2(d, "a: x", "b: y", "c")) // -> { x: "1", c: "2" }
I required this sollution but I didn't knew if the proposed keys were available. So, I took #torazaburo answer and improved for my use case:
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => {
if (o[prop]) return {[prop]: o[prop]};
}));
}
// Example:
var person = { name: 'John', age: 29 };
var myObj = pick(person, 'name', 'sex'); // { name: 'John' }
Some great solutions above, didn't see one for Typescript fleshed out, so here it goes. Based on #Ethan Browns solution above
const pick = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Pick< T, K > =>
keys.reduce< any >( ( r, key ) => {
r[ key ] = obj[ key ];
return r;
}, {} );
And for bonus, here is TS friendly es6 omit, and one that is much more performant below, but less es6.
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > =>
keys.reduce( ( r, key ) => ( delete r[ key ], r ), {
...obj,
} );
Way more performant omit: http://jsben.ch/g6QCK
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > => {
let r: any = {};
let length = keys.length;
while ( length-- ) {
const key = keys[ length ];
r[ key ] = obj[ key ];
}
return r;
};
inspired by the reduce approach of https://stackoverflow.com/users/865693/shesek:
const pick = (orig, keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})
or even slightly shorter using the comma operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator)
const pick = (obj, keys) => keys.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
usage:
pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear')
results in:
{model: "F40", productionYear: 1987}
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 };
}
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)})))
);
}
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');
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"}
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')
)
ES6 was the latest spec at the time when the question was written. As explained in this answer, key picking is significantly shorter in ES2019 than in ES6:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
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.)
You can use object destructuring to unpack properties from the existing object and assign them to variables with different names - fields of a new, initially empty object.
const person = {
fname: 'tom',
lname: 'jerry',
aage: 100,
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
There's currently a strawman proposal for improving JavaScript's object shorthand syntax, which would enable "picking" of named properties without repetition:
const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});
console.log(picked);
// {id: "68646", title: "Scarface"}
Unfortunately, the proposal doesn't seem to be going anywhere any time soon. Last edited in July 2017 and still a draft at Stage 0, suggesting the author may have ditched or forgotten about it.
ES5 and earlier (non-strict mode)
The concisest possible shorthand I can think of involves an ancient language feature nobody uses anymore:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
with statements are forbidden in strict mode, making this approach useless for 99.999% of modern JavaScript. Bit of a shame, because this is the only halfway-decent use I've found for the with feature. 😀
I have similar to Ethan Brown's solution, but even shorter - pick function. Another function pick2 is a bit longer (and slower), but allows to rename properties in the similar to ES6 manner.
const pick = (o, ...props) => props.reduce((r, p) => p in o ? {...r, [p]: o[p]} : r, {})
const pick2 = (o, ...props) => props.reduce((r, expr) => {
const [p, np] = expr.split(":").map( e => e.trim() )
return p in o ? {...r, [np || p]: o[p]} : r
}, {})
Here is the usage example:
const d = { a: "1", c: "2" }
console.log(pick(d, "a", "b", "c")) // -> { a: "1", c: "2" }
console.log(pick2(d, "a: x", "b: y", "c")) // -> { x: "1", c: "2" }
I required this sollution but I didn't knew if the proposed keys were available. So, I took #torazaburo answer and improved for my use case:
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => {
if (o[prop]) return {[prop]: o[prop]};
}));
}
// Example:
var person = { name: 'John', age: 29 };
var myObj = pick(person, 'name', 'sex'); // { name: 'John' }
Some great solutions above, didn't see one for Typescript fleshed out, so here it goes. Based on #Ethan Browns solution above
const pick = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Pick< T, K > =>
keys.reduce< any >( ( r, key ) => {
r[ key ] = obj[ key ];
return r;
}, {} );
And for bonus, here is TS friendly es6 omit, and one that is much more performant below, but less es6.
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > =>
keys.reduce( ( r, key ) => ( delete r[ key ], r ), {
...obj,
} );
Way more performant omit: http://jsben.ch/g6QCK
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > => {
let r: any = {};
let length = keys.length;
while ( length-- ) {
const key = keys[ length ];
r[ key ] = obj[ key ];
}
return r;
};
inspired by the reduce approach of https://stackoverflow.com/users/865693/shesek:
const pick = (orig, keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})
or even slightly shorter using the comma operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator)
const pick = (obj, keys) => keys.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
usage:
pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear')
results in:
{model: "F40", productionYear: 1987}
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 };
}
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)})))
);
}
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');
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"}
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')
)
ES6 was the latest spec at the time when the question was written. As explained in this answer, key picking is significantly shorter in ES2019 than in ES6:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
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.)
You can use object destructuring to unpack properties from the existing object and assign them to variables with different names - fields of a new, initially empty object.
const person = {
fname: 'tom',
lname: 'jerry',
aage: 100,
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
There's currently a strawman proposal for improving JavaScript's object shorthand syntax, which would enable "picking" of named properties without repetition:
const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});
console.log(picked);
// {id: "68646", title: "Scarface"}
Unfortunately, the proposal doesn't seem to be going anywhere any time soon. Last edited in July 2017 and still a draft at Stage 0, suggesting the author may have ditched or forgotten about it.
ES5 and earlier (non-strict mode)
The concisest possible shorthand I can think of involves an ancient language feature nobody uses anymore:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
with statements are forbidden in strict mode, making this approach useless for 99.999% of modern JavaScript. Bit of a shame, because this is the only halfway-decent use I've found for the with feature. 😀
I have similar to Ethan Brown's solution, but even shorter - pick function. Another function pick2 is a bit longer (and slower), but allows to rename properties in the similar to ES6 manner.
const pick = (o, ...props) => props.reduce((r, p) => p in o ? {...r, [p]: o[p]} : r, {})
const pick2 = (o, ...props) => props.reduce((r, expr) => {
const [p, np] = expr.split(":").map( e => e.trim() )
return p in o ? {...r, [np || p]: o[p]} : r
}, {})
Here is the usage example:
const d = { a: "1", c: "2" }
console.log(pick(d, "a", "b", "c")) // -> { a: "1", c: "2" }
console.log(pick2(d, "a: x", "b: y", "c")) // -> { x: "1", c: "2" }
I required this sollution but I didn't knew if the proposed keys were available. So, I took #torazaburo answer and improved for my use case:
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => {
if (o[prop]) return {[prop]: o[prop]};
}));
}
// Example:
var person = { name: 'John', age: 29 };
var myObj = pick(person, 'name', 'sex'); // { name: 'John' }
Some great solutions above, didn't see one for Typescript fleshed out, so here it goes. Based on #Ethan Browns solution above
const pick = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Pick< T, K > =>
keys.reduce< any >( ( r, key ) => {
r[ key ] = obj[ key ];
return r;
}, {} );
And for bonus, here is TS friendly es6 omit, and one that is much more performant below, but less es6.
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > =>
keys.reduce( ( r, key ) => ( delete r[ key ], r ), {
...obj,
} );
Way more performant omit: http://jsben.ch/g6QCK
const omit = < T extends object, K extends keyof T >(
obj: T,
...keys: K[]
): Omit< T, K > => {
let r: any = {};
let length = keys.length;
while ( length-- ) {
const key = keys[ length ];
r[ key ] = obj[ key ];
}
return r;
};
inspired by the reduce approach of https://stackoverflow.com/users/865693/shesek:
const pick = (orig, keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})
or even slightly shorter using the comma operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator)
const pick = (obj, keys) => keys.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
usage:
pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear')
results in:
{model: "F40", productionYear: 1987}