ES6 desestruturação
A sintaxe da reestruturação permite desestruturar e recombinar um objeto, com parâmetros ou variáveis de função.
A limitação é que uma lista de chaves é predefinida, elas não podem ser listadas como seqüências de caracteres, conforme mencionado na pergunta. A reestruturação se torna mais complicada se uma chave não é alfanumérica, por exemplo foo_bar
.
A desvantagem é que isso requer duplicar uma lista de chaves, resultando em código detalhado, caso uma lista seja longa. Como a desestruturação duplica a sintaxe literal do objeto nesse caso, uma lista pode ser copiada e colada como está.
A vantagem é que é uma solução de alto desempenho que é natural para o ES6.
IIFE
let subset = (({ foo, bar }) => ({ foo, bar }))(obj); // dupe ({ foo, bar })
Variáveis temporárias
let { foo, bar } = obj;
let subset = { foo, bar }; // dupe { foo, bar }
Uma lista de strings
A lista arbitrária de chaves selecionadas consiste em seqüências de caracteres, conforme a pergunta. Isso permite não predefini-los e usar variáveis que contêm nomes de chave, comopick(obj, 'foo', someKey, ...moreKeys)
.
Um one-liner fica mais curto a cada edição JS.
ES5
var subset = Object.keys(obj)
.filter(function (key) {
return ['foo', 'bar'].indexOf(key) >= 0;
})
.reduce(function (obj2, key) {
obj2[key] = obj[key];
return obj2;
}, {});
ES6
let subset = Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => Object.assign(obj2, { [key]: obj[key] }), {});
Ou com o operador de vírgula:
let subset = Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => (obj2[key] = obj[key], obj2), {});
ES2019
O ECMAScript 2017 possui Object.entries
e Array.prototype.includes
, o ECMAScript 2019 possui Object.fromEntries
, eles podem ser polyfilled quando necessário e facilitar a tarefa:
let subset = Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
Um one-liner pode ser reescrito como função auxiliar semelhante ao Lodashpick
ou omit
onde a lista de chaves é passada através de argumentos:
let pick = (obj, ...keys) => Object.fromEntries(
Object.entries(obj)
.filter(([key]) => keys.includes(key))
);
let subset = pick({ foo: 1, qux: 2 }, 'foo', 'bar'); // { foo: 1 }
Uma observação sobre falta de chaves
A principal diferença entre a desestruturação e a função convencional do tipo Lodash pick
é que a desestruturação inclui chaves selecionadas inexistentes com undefined
valor em um subconjunto:
(({ foo, bar }) => ({ foo, bar }))({ foo: 1 }) // { foo: 1, bar: undefined }
Esse comportamento pode ou não ser desejável. Não pode ser alterado para desestruturar a sintaxe.
Enquanto pick
pode ser alterado para incluir chaves ausentes, iterando uma lista de chaves selecionadas:
let inclusivePick = (obj, ...keys) => Object.fromEntries(
keys.map(key => [key, obj[key]])
);
let subset = inclusivePick({ foo: 1, qux: 2 }, 'foo', 'bar'); // { foo: 1, bar: undefined }