104

Come si può scrivere una funzione, che richiede solo pochi attributi in modo più compatto in ES6?One-liner per acquisire alcune proprietà dall'oggetto in ES 6

Mi è venuta in mente una soluzione che utilizza la destrutturazione + oggetto semplificato letterale, ma non mi piace che l'elenco di campi venga ripetuto nel codice.

C'è una soluzione ancora più sottile?

(v) => { 
    let { id, title } = v; 
    return { id, title }; 
} 
+0

mi sono trovato che vogliono fare proprio questo. –

risposta

84

Ecco qualcosa di più sottile, anche se non evita di ripetere l'elenco dei campi. Utilizza "destrutturazione dei parametri" per evitare la necessità del parametro v.

({id, title}) => ({id, title}) 

@ La soluzione di EthanBrown è più generale. Ecco una versione più idiomatica di esso che utilizza Object.assign, e le proprietà computerizzata (la [p] parte):

function pick(o, ...props) { 
    return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]}))); 
} 

Se vogliamo conservare gli attributi le proprieta, come configurable e getter e setter, ma anche omettendo non proprietà -enumerable, allora:

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)}))) 
    ); 
} 
+6

+1 bella risposta, torazaburo; grazie per avermi reso consapevole di 'Object.assign'; es6 è come un albero di Natale con tanti regali sotto di esso Sto ancora trovando regali mesi dopo la vacanza –

+0

Hai un errore: La descrizione della proprietà deve essere un oggetto: non definito. Non dovrebbe essere 'filtro (...). Mappa (prop => ({[prop]: get (prop)})))'? – Endless

+0

Per la tua prima implementazione di 'pick()' potresti anche fare qualcosa come 'return props.reduce ((r, prop) => (r [prop] = o [prop], r), {})' –

32

non credo che ci sia alcun modo per rendere molto più compatta rispetto la risposta (o torazburo di), ma essenzialmente quello che stai cercando di fare è emulare Underscore's pick operation. Sarebbe abbastanza facile re-implementare che in ES6:

function pick(o, ...fields) { 
    return fields.reduce((a, x) => { 
     if(o.hasOwnProperty(x)) a[x] = o[x]; 
     return a; 
    }, {}); 
} 

allora si ha un portata di mano riutilizzabile funzione:

var stuff = { name: 'Thing', color: 'blue', age: 17 }; 
var picked = pick(stuff, 'name', 'age'); 
+0

Grazie. Questa non è una risposta per la mia domanda, ma molto bella aggiunta. – kirilloid

+4

(scrollata di spalle) Mi sento come se fosse una risposta alla tua soluzione; non esiste una soluzione _general_ più snella (la soluzione di torazaburo rimuove dal verbage in più, ma il problema essenziale - che tutti i nomi di proprietà devono essere scritti due volte - significa che non ha una scala migliore della soluzione). La mia soluzione almeno si adatta bene ... con la funzione 'pick' una volta, e puoi scegliere quante proprietà vuoi e non raddoppiarle. –

+1

Perché usi 'hasOwnProperty'? Se i campi sono selezionati a mano, anche 'in' sembra essere più appropriato; anche se andrei a omettere completamente il controllo e gli permetterò di default "non definito". – Bergi

0

devo simile alla soluzione di Ethan Brown, ma ancora più brevi - pick funzione. Un'altra funzione pick2 è un po 'più lunga (e più lenta), ma consente di rinominare le proprietà in modo simile a 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 
}, {}) 

Ecco l'esempio di utilizzo:

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

Qual è la ragione per downvote? Non funziona per te? –

12

Il trucco per risolvere questo come una battuta è quello di capovolgere l'approccio: Invece di partire dall'oggetto originale orig, si può iniziare dalla le chiavi che vogliono estrarre.

Utilizzando Array#reduce, è possibile quindi memorizzare ciascuna chiave necessaria sull'oggetto vuoto che viene passato come initialValue per la suddetta funzione.

Come così:

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

5

TC39's object rest/spread properties proposal renderà questo abbastanza liscia:

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; 
z; // { a: 3, b: 4 } 

(Esso ha il lato negativo di creare le x e y variabili che si possono non è necessario.)

+18

Questa è una comoda forma di 'omissione', ma non 'scelta' – kirilloid

0

Ho richiesto questa soluzione ma non sapevo se le chiavi proposte fossero disponibili. Così, ho preso risposta @torazaburo e migliorato per il mio caso d'uso:

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

Una soluzione po 'più breve minuscola utilizzando l'operatore virgola:

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

come usare questo? Puoi fornire un esempio? –

+0

Funziona esattamente come le altre funzioni 'pick' in questo thread:' pick ({nome: 'John', età: 29, altezza: 198}, 'nome', 'età') ' – shesek

Problemi correlati