Wie kann man eine Funktion schreiben, die in ES6 auf kompakteste Weise nur wenige Attribute benötigt?
Ich habe eine Lösung mit Destructuring + vereinfachtem Objektliteral gefunden, aber ich mag es nicht, dass die Liste der Felder im Code wiederholt wird.
Gibt es eine noch schlankere Lösung?
(v) => {
let { id, title } = v;
return { id, title };
}
Hier ist etwas Schlankeres, obwohl die Liste der Felder nicht wiederholt werden muss. Es verwendet "Parameter-Destrukturierung", um die Notwendigkeit des Parameters v
zu vermeiden.
({id, title}) => ({id, title})
Die Lösung von @ethanBrown ist allgemeiner. Hier ist eine idiomatischere Version davon, die Object.assign
und berechnete Eigenschaften (der [p]
-Teil) verwendet:
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})));
}
Wenn wir die Attribute der Eigenschaften, wie configurable
und Getter und Setter, beibehalten möchten, und dabei auch nicht aufzuzählende Eigenschaften weglassen möchten,
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)})))
);
}
Ich glaube nicht, dass es eine Möglichkeit gibt, sie viel kompakter zu gestalten als Ihre Antwort (oder Torazburos), aber im Wesentlichen möchten Sie mit Underscores pick
operation emulieren. Es wäre leicht genug, das in ES6 neu zu implementieren:
function pick(o, ...fields) {
return fields.reduce((a, x) => {
if(o.hasOwnProperty(x)) a[x] = o[x];
return a;
}, {});
}
Dann haben Sie eine praktische wiederverwendbare Funktion:
var stuff = { name: 'Thing', color: 'blue', age: 17 };
var picked = pick(stuff, 'name', 'age');
Der Trick, um dies als Einzeiler zu lösen, besteht darin, den gewählten Ansatz umzudrehen: Anstatt mit dem ursprünglichen Objekt orig
zu beginnen, kann man von den Schlüsseln ausgehen, 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 die Funktion übergeben wird.
So wie:
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"}
Eine kleine, etwas kürzere Lösung mit dem Komma-Operator:
const pick = (O, ...K) => K.reduce((o, k) => (o[k]=O[k], o), {})
TC39s Objektrest/Spread-Eigenschaftsvorschlag macht dies ziemlich glatt:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
z; // { a: 3, b: 4 }
(Es hat den Nachteil, dass Sie die Variablen x
und y
erstellen, die Sie möglicherweise nicht benötigen.)
Derzeit gibt es einen Strawman-Vorschlag zur Verbesserung der JavaScript-Syntax für Objektkurzzeichen, mit dem benannte Eigenschaften ohne Wiederholung ausgewählt werden können:
const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});
console.log(picked);
// {id: "68646", title: "Scarface"}
Leider scheint der Vorschlag in absehbarer Zeit keine Wirkung zu entfalten. Zuletzt bearbeitet im Juli 2017 und immer noch ein Entwurf bei Stufe , was darauf hindeutet, dass der Autor es vielleicht vergessen oder vergessen hat.
Die knappste mögliche Abkürzung, die ich mir vorstellen kann, beinhaltet ein altes Sprachmerkmal das niemand mehr benutzt:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
with
-Anweisungen sind im strikten Modus verboten, sodass dieser Ansatz für 99,999% des modernen JavaScript unbrauchbar ist. Etwas schade, denn dies ist die einzige halbwegs anständige Verwendung, die ich für die Funktion with
gefunden habe. ????
ES6 war die neueste Spezifikation zu dem Zeitpunkt, als die Frage geschrieben wurde. Wie in diese Antwort erläutert, ist die Schlüsselauswahl in ES2019 erheblich kürzer als in ES6:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
Eine Möglichkeit könnte darin bestehen, destructuring
zu verwenden, um einem leeren Objekt Eigenschaften zuzuweisen.
let person = {
fname:'tom',
lname:'jerry',
aage:100
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
Ich habe eine ähnliche Lösung wie die Lösung von Ethan Brown, aber noch kürzer - pick
-Funktion. Eine andere Funktion pick2
ist etwas länger (und langsamer), ermöglicht jedoch das Umbenennen von Eigenschaften auf ähnliche Weise wie bei 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
}, {})
Hier ist das Anwendungsbeispiel:
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" }
Ich habe diese Lösung benötigt, wusste aber nicht, ob die vorgeschlagenen Schlüssel verfügbar sind. Also nahm ich die Antwort von @torazaburo und verbesserte mich 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' }
inspiriert durch den Reduktionsansatz von https://stackoverflow.com/users/865693/shesek :
const pick = (orig, ...keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})
verwendungszweck:
pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear')
führt zu: {model: "F40", productionYear: 1987}