web-dev-qa-db-fra.com

One-Liner pour extraire certaines propriétés d'objet dans ES 6

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 };
}
131
kirilloid

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)})))
    );
}
98
user663031

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');
39
Ethan Brown

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"}

17
Bramus

Une solution un peu plus courte utilisant l'opérateur virgule:

const pick = (O, ...K) => K.reduce((o, k) => (o[k]=O[k], o), {})
8
shesek

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

6
alxndr

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.

ES5 et versions antérieures (mode non strict)

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

1
user458541

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))
)
1
Estus Flask

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);
1
Saksham

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" }
1
Alexandr Priezzhev

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' }
0
Alwin Kesler

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}

0
Kevin K.