104

Wie kann man eine Funktion schreiben, die in ES6 nur sehr wenige Attribute auf kompakteste Weise aufnimmt?Ein-Liner um einige Eigenschaften vom Objekt in ES 6 zu übernehmen

Ich habe eine Lösung mit Destrukturierung + vereinfachtes Objektliteral gefunden, aber ich mag es nicht, dass diese Liste von Feldern im Code wiederholt wird.

Gibt es eine noch schlankere Lösung?

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

Ich habe festgestellt, ich diese gerade tun will. –

Antwort

84

Hier ist etwas schlanker, obwohl es nicht vermeidet, die Liste der Felder zu wiederholen. Es verwendet "Parameter-Destrukturierung", um den Parameter v zu vermeiden.

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

@ EthanBrowns Lösung ist allgemeiner. Hier ist eine idiomatische Version davon, die Object.assign verwendet, und berechnete Eigenschaften (der [p] Teil):

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

Wenn wir die Eigenschaften Attribute wie configurable und Getter und Setter, erhalten wollen, während auch nicht Weglassen -enumerable Eigenschaften, dann:

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 nette Antwort, torazaburo; Danke, dass du mich auf "Object.assign" aufmerksam gemacht hast. es6 ist wie ein Weihnachtsbaum mit so vielen Geschenken darunter finde ich noch Monate nach dem Urlaub Geschenke. –

+0

Fehler: Objektbeschreibung muss ein Objekt sein: undefiniert. Sollte es nicht 'filter (...) sein. Map (prop => ({[prop]: get (prop)})))? – Endless

+0

Für Ihre erste 'pick()' Implementierung könnten Sie auch etwas wie 'return props.reduce ((r, prop) => (r [prop] = o [prop], r), {})' –

32

ich glaube nicht, dass es eine Möglichkeit, es zu machen, viel kompakter als die Antwort (oder torazburo ist), aber im wesentlichen, was Sie versuchen Underscore's pick operation zu tun ist, zu emulieren. Es wäre leicht genug, um neu zu implementieren, dass in ES6:

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

Dann Sie eine handliche wiederverwendbare Funktion haben:

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

Danke. Dies ist keine Antwort auf meine Frage, aber sehr nette Ergänzung. – kirilloid

+4

(Achselzucken) Ich fühle mich wie es _is_ eine Antwort für Ihre Lösung ist; es gibt keine schlankere _allgemein_ Lösung (torazaburos Lösung entfernt den zusätzlichen Verba, aber das wesentliche Problem - dass alle Eigenschaftsnamen zweimal geschrieben werden müssen - bedeutet, dass es nicht besser skaliert als Ihre Lösung). Meine Lösung skaliert zumindest gut ... rechts die "Pick" -Funktion einmal, und Sie können so viele Eigenschaften auswählen, wie Sie wollen und es wird nicht verdoppelt. –

+1

Warum benutzen Sie 'hasOwnProperty'? Wenn die Felder handselektiert sind, scheint sogar 'in' geeigneter zu sein; obwohl ich den Check ganz weglassen würde und sie einfach auf "undefiniert" setzen lassen würde. – Bergi

0

Ich habe ähnlich wie Ethan Brown-Lösung, aber auch kürzer - pick Funktion. Eine andere Funktion pick2 ist ein bisschen länger (und langsamer), aber ermöglicht es, Eigenschaften in der ES6 ähnlichen Weise umzubenennen. Hier

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 
}, {}) 

ist das Verwendungsbeispiel:

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

Was ist der Grund für den Downvote? Funktioniert es nicht für dich? –

12

Der Trick dies als Einzeiler zu lösen, ist die Annäherung an Flip genommen: Statt von den ursprünglichen Objekt beginnend orig, kann man von Anfang an Schlüssel, die sie extrahieren möchten.

Mit Array#reduce kann man dann jeden benötigten Schlüssel auf dem leeren Objekt speichern, das als initialValue für diese Funktion übergeben wird.

Wie so:

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 diese ziemlich glatt machen:

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

(es hat den Nachteil der Erzeugung der x und y Variablen, die können Sie nicht brauchen.)

+18

Dies ist eine bequeme Form von "weglassen", aber nicht "picken" – kirilloid

0

Ich brauchte diese Lösung, aber ich wusste nicht, ob die vorgeschlagenen Schlüssel verfügbar waren. Also nahm ich @torazaburo Antwort und verbessern für meinen Anwendungsfall:

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

Eine kleine bisschen kürzer Lösung mit dem Komma-Operator:

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

, wie man das verwendet? Können Sie ein Beispiel geben? –

+0

Es funktioniert genau wie die anderen "Pick" -Funktionen in diesem Thread: 'pick ({Name: 'John', Alter: 29, Höhe: 198}, 'Name', 'Alter')' – shesek