Comment écrire une fonction qui ne prend que quelques attributs de la manière la plus compacte dans ES6?
J'ai trouvé une solution en utilisant destructuring + littéral d'objet simplifié, mais je n'aime pas que la liste des champs soit répétée dans le code.
Y a-t-il une solution encore plus fine?
(v) => {
let { id, title } = v;
return { id, title };
}
Voici quelque chose de plus mince, bien que cela n'empêche pas de répéter la liste des champs. Il utilise la "déstructuration des paramètres" pour éviter la nécessité du paramètre v
.
({id, title}) => ({id, title})
La solution de @ EthanBrown est plus générale. Voici une version plus idiomatique de celui-ci qui utilise Object.assign
et les propriétés calculées (la partie [p]
):
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})));
}
Si nous voulons préserver les attributs des propriétés, tels que configurable
et les getters et setters, tout en omettant les propriétés non énumérables, alors:
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)})))
);
}
Je ne pense pas qu'il soit possible de la rendre beaucoup plus compacte que votre réponse (ou celle de torazburo), mais vous voulez essentiellement imiter l'opération pick
de Underscore . Il serait assez facile de ré-implémenter cela dans ES6:
function pick(o, ...fields) {
return fields.reduce((a, x) => {
if(o.hasOwnProperty(x)) a[x] = o[x];
return a;
}, {});
}
Ensuite, vous avez une fonction réutilisable pratique:
var stuff = { name: 'Thing', color: 'blue', age: 17 };
var picked = pick(stuff, 'name', 'age');
Le truc pour résoudre ce problème en une ligne est de renverser l’approche choisie: au lieu de partir de l’objet original orig
, on peut partir des clés qu’ils veulent extraire.
En utilisant Array#reduce
on peut alors stocker chaque clé nécessaire sur l’objet vide qui est passé sous la forme initialValue
pour ladite fonction.
Ainsi:
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"}
Une solution un peu plus courte utilisant l'opérateur virgule:
const pick = (O, ...K) => K.reduce((o, k) => (o[k]=O[k], o), {})
La proposition de propriétés de l'objet repos/propagation de TC39 rendra cette jolie nappe:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
z; // { a: 3, b: 4 }
(Il a l'inconvénient de créer les variables x
et y
dont vous n'avez peut-être pas besoin.)
Il existe actuellement une proposition strawman destinée à améliorer la syntaxe abrégée de l'objet JavaScript, qui permettrait de "sélectionner" les propriétés nommées sans répétition:
const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});
console.log(picked);
// {id: "68646", title: "Scarface"}
Malheureusement, la proposition ne semble pas aller n'importe où bientôt. Dernière édition en juillet 2017 et toujours un brouillon à Stage , suggérant que l'auteur a peut-être abandonné ou oublié cela.
Le raccourci le plus conciliant auquel je puisse penser implique un fonctionnalité de langue ancienne personne ne l'utilise plus:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
Les instructions with
sont interdites en mode strict, rendant cette approche inutile pour 99,999% du JavaScript moderne. Un peu dommage, car c’est la seule utilisation à peu près décente que j’ai trouvée pour la fonction with
. ????
ES6 était la dernière spécification au moment où la question a été écrite. Comme expliqué dans cette réponse , la sélection des clés est nettement plus courte dans ES2019 que dans ES6:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
Un moyen pourrait être d'utiliser destructuring
pour affecter des propriétés à un objet vide.
let person = {
fname:'tom',
lname:'jerry',
aage:100
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
J'ai une solution similaire à celle d'Ethan Brown, mais encore plus courte - fonction pick
. Une autre fonction pick2
est un peu plus longue (et plus lente), mais permet de renommer les propriétés de la même manière que ES6.
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
}, {})
Voici l'exemple d'utilisation:
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" }
J'avais besoin de cette solution mais je ne savais pas si les clés proposées étaient disponibles. Donc, j'ai pris la réponse @torazaburo et amélioré pour mon cas d'utilisation:
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' }
inspiré par l'approche de réduction de https://stackoverflow.com/users/865693/shesek :
const pick = (orig, ...keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})
usage:
pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear')
résulte en: {model: "F40", productionYear: 1987}