ES6 desestructuración
La sintaxis de desestructuración permite desestructurar y recombinar un objeto, ya sea con parámetros de función o variables.
La limitación es que una lista de claves está predefinida, no se pueden enumerar como cadenas, como se menciona en la pregunta. La desestructuración se vuelve más complicada si una clave no es alfanumérica, por ejemplo foo_bar
.
La desventaja es que esto requiere duplicar una lista de claves, esto da como resultado un código detallado en caso de que una lista sea larga. Dado que la desestructuración de la sintaxis literal de objetos duplicados en este caso, una lista se puede copiar y pegar tal cual.
Lo bueno es que es una solución eficaz que es natural para ES6.
IIFE
let subset = (({ foo, bar }) => ({ foo, bar }))(obj); // dupe ({ foo, bar })
Variables temporales
let { foo, bar } = obj;
let subset = { foo, bar }; // dupe { foo, bar }
Una lista de cadenas
La lista arbitraria de claves seleccionadas consta de cadenas, según lo requiera la pregunta. Esto permite no predefinirlos y usar variables que contienen nombres clave, como pick(obj, 'foo', someKey, ...moreKeys)
.
Una línea se acorta con cada edición de 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] }), {});
O con operador de coma:
let subset = Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => (obj2[key] = obj[key], obj2), {});
ES2019
ECMAScript 2017 tiene Object.entries
y Array.prototype.includes
, ECMAScript 2019 tiene Object.fromEntries
, se pueden rellenar cuando sea necesario y facilitar la tarea:
let subset = Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
Un one-liner se puede reescribir como una función auxiliar similar a Lodashpick
o omit
donde la lista de claves se pasa a travé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 }
Una nota sobre las llaves faltantes
La principal diferencia entre la desestructuración y la función convencional similar a Lodash pick
es que la desestructuración incluye claves recogidas inexistentes con undefined
valor en un subconjunto:
(({ foo, bar }) => ({ foo, bar }))({ foo: 1 }) // { foo: 1, bar: undefined }
Este comportamiento puede o no ser deseable. No se puede cambiar por la sintaxis de desestructuración.
Mientras que pick
se puede cambiar para incluir claves faltantes iterando una lista de claves elegidas en su lugar:
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 }