Zwei gängige Ansätze sind Destrukturierung und konventionelle Lodash-ähnliche pick
/omit
Implementierung. Der wichtigste praktische Unterschied zwischen ihnen besteht darin, dass Destrukturierung eine Liste von Schlüsseln erfordert, die statisch sein müssen, nicht weggelassen werden können, beinhaltet nicht existierende ausgewählte Schlüssel, d.h. sie ist inklusiv. Dies kann wünschenswert sein oder auch nicht, und kann für die Destrukturierungssyntax nicht geändert werden.
Gegeben:
var obj = { 'foo-bar': 1, bar: 2, qux: 3 };
Das erwartete Ergebnis für das reguläre Auswählen der Schlüssel foo-bar
, bar
, baz
lautet:
{ 'foo-bar': 1, bar: 2 }
Das erwartete Ergebnis für das inklusive Auswählen lautet:
{ 'foo-bar': 1, bar: 2, baz: undefined }
Destrukturierung
Die Destrukturierungssyntax ermöglicht es, ein Objekt zu zerlegen und neu zu kombinieren, entweder mit Funktionsparametern oder Variablen.
Die Einschränkung besteht darin, dass eine Liste von Schlüsseln vordefiniert ist, sie können nicht als Zeichenfolgen aufgelistet werden, wie in der Frage beschrieben. Destrukturierung wird komplizierter, wenn ein Schlüssel nicht alphanumerisch ist, z.B. foo-bar
.
Der Vorteil ist, dass es eine performante Lösung ist, die nativ in ES6 ist.
Der Nachteil ist, dass eine Liste von Schlüsseln dupliziert wird, was zu einem umständlichen Code führt, wenn die Liste lang ist. Da die Destrukturierung in diesem Fall das Objektliteral dupliziert, kann die Liste einfach kopiert und eingefügt werden.
IIFE
const subset = (({ 'foo-bar': foo, bar, baz }) => ({ 'foo-bar': foo, bar, baz }))(obj);
Temporäre Variablen
Kann zur Kollision von Variablennamen im aktuellen Bereich führen:
const { 'foo-bar': foo, bar, baz } = obj;
const subset = { 'foo-bar': foo, bar, baz };
Blockebene kann verwendet werden, um dies zu vermeiden:
let subset;
{
const { 'foo-bar': foo, bar, baz } = obj;
subset = { 'foo-bar': foo, bar, baz };
}
Eine Liste von Zeichenfolgen
Eine beliebige Liste von ausgewählten Schlüsseln besteht aus Zeichenfolgen, wie in der Frage gefordert. Dies ermöglicht es, sie nicht vordefinieren zu müssen und Variablen zu verwenden, die Schlüsselnamen enthalten, ['foo-bar', someKey, ...moreKeys]
.
ECMAScript 2017 hat Object.entries
und Array.prototype.includes
, ECMAScript 2019 hat Object.fromEntries
, sie können bei Bedarf polyfilled werden.
Einzeiler
Angesichts der Tatsache, dass ein Objekt zum Auswählen zusätzliche Schlüssel enthält, ist es im Allgemeinen effizienter, über Schlüssel aus einer Liste zu iterieren als über Objektschlüssel, und umgekehrt, wenn Schlüssel ausgelassen werden müssen.
Pick (ES5)
var subset = ['foo-bar', 'bar', 'baz']
.reduce(function (obj2, key) {
if (key in obj) // Zeile kann entfernt werden, um sie inklusiv zu machen
obj2[key] = obj[key];
return obj2;
}, {});
Omit (ES5)
var subset = Object.keys(obj)
.filter(function (key) {
return ['baz', 'qux'].indexOf(key) < 0;
})
.reduce(function (obj2, key) {
obj2[key] = obj[key];
return obj2;
}, {});
Pick (ES6)
const subset = ['foo-bar', 'bar', 'baz']
.filter(key => key in obj) // Zeile kann entfernt werden, um sie inklusiv zu machen
.reduce((obj2, key) => (obj2[key] = obj[key], obj2), {});
Omit (ES6)
const subset = Object.keys(obj)
.filter(key => ['baz', 'qux'].indexOf(key) < 0)
.reduce((obj2, key) => (obj2[key] = obj[key], obj2), {});
Pick (ES2019)
const subset = Object.fromEntries(
['foo-bar', 'bar', 'baz']
.filter(key => key in obj) // Zeile kann entfernt werden, um sie inklusiv zu machen
.map(key => [key, obj[key]])
);
Omit (ES2019)
const subset = Object.fromEntries(
Object.entries(obj)
.filter(([key]) => !['baz', 'qux'].includes(key))
);
Wiederverwendbare Funktionen
Einzeiler können als wiederverwendbare Hilfsfunktionen dargestellt werden, ähnlich wie Lodash pick
oder omit
, wobei eine Liste von Schlüsseln über Argumente übergeben wird, pick(obj, 'foo-bar', 'bar', 'baz')
.
JavaScript
const pick = (obj, ...keys) => Object.fromEntries(
keys
.filter(key => key in obj)
.map(key => [key, obj[key]])
);
const inclusivePick = (obj, ...keys) => Object.fromEntries(
keys.map(key => [key, obj[key]])
);
const omit = (obj, ...keys) => Object.fromEntries(
Object.entries(obj)
.filter(([key]) => !keys.includes(key))
);
TypeScript
Gutschrift geht an @Claude.
const pick = (obj: T, ...keys: K[]) => (
Object.fromEntries(
keys
.filter(key => key in obj)
.map(key => [key, obj[key]])
) as Pick
);
const inclusivePick = (
obj: T, ...keys: K[]
) => (
Object.fromEntries(
keys
.map(key => [key, obj[key as unknown as keyof T]])
) as {[key in K]: key extends keyof T ? T[key] : undefined}
)
const omit = (
obj: T, ...keys: K[]
) =>(
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => !keys.includes(key as K))
) as Omit
)