Wie kann ich ein JavaScript-Objekt bis auf einen Schlüssel klonen?

308

Ich habe ein flaches JS-Objekt:

{a: 1, b: 2, c: 3, ..., z:26}

Ich möchte das Objekt bis auf ein Element klonen:

{a: 1, c: 3, ..., z:26}

Was ist der einfachste Weg, dies zu tun (wenn möglich lieber es6 / 7 zu verwenden)?

Fuchs
quelle
Ohne das ursprüngliche Objekt zu ändern: JSON.parse (JSON.stringify ({... obj, 'key2': undefined}))
unendlich1975

Antworten:

441

Wenn Sie Babel verwenden , können Sie die folgende Syntax verwenden, um die Eigenschaft b von x in die Variable b zu kopieren und die restlichen Eigenschaften in die Variable y zu kopieren :

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

und es wird umgesetzt in:

"use strict";

function _objectWithoutProperties(obj, keys) {
  var target = {};
  for (var i in obj) {
    if (keys.indexOf(i) >= 0) continue;
    if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
    target[i] = obj[i];
  }
  return target;
}

var x = { a: 1, b: 2, c: 3, z: 26 };
var b = x.b;

var y = _objectWithoutProperties(x, ["b"]);
Ilya Palkin
quelle
58
Wenn Sie Ihren Code für nicht verwendete Variablen fusseln, führt dies zu einer "nicht verwendeten Variablen 'b'". Warnung jedoch.
Ross Allen
1
Wie würde die Syntax aussehen, wenn Sie hättenlet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup
14
@ RossAllen Es gibt eine Option ignoreRestSiblings, die in Version 3.15.0 (3. Februar 2017) hinzugefügt wurde. Siehe: Commit c59a0ba
Ilya Palkin
4
@ IlyaPalkin Interessant. Es fühlt sich allerdings etwas faul an, weil es nichts an der Tatsache ändert, dass es einen bUmfang gibt.
Ross Allen
2
Wenn die Modulerstellung fehlgeschlagen ist: SyntaxError: Unerwartetes Token, müssen Sie wahrscheinlich das Transformations-Plugin für die Babel Rest Spread hinzufügen. Siehe babeljs.io/docs/plugins/transform-object-rest-spread
jsaven
133
var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

oder wenn Sie akzeptieren, dass Eigentum undefiniert ist:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});
madox2
quelle
7
Das einfache Löschen der Eigenschaft ist eine klare und einfache Möglichkeit, dies zu tun.
Show
24
Die Einschränkung beim Löschen ist, dass es sich nicht um eine unveränderliche Operation handelt.
Javid Jamae
1
Dies hält den Schlüssel
Fareed Alnamrouti
1
Mein Kommentar wurde geschrieben, bevor er seine Antwort bearbeitet und die
Löschanweisung
Dies ist genau das, wonach ich gesucht habe, aber etwas anders implementiert: var cake = {... currentCake, requestorId: undefined};
Abelito
73

Um Ilya Palkins Antwort zu ergänzen: Sie können sogar Schlüssel dynamisch entfernen:

const x = {a: 1, b: 2, c: 3, z:26};

const objectWithoutKey = (object, key) => {
  const {[key]: deletedKey, ...otherKeys} = object;
  return otherKeys;
}

console.log(objectWithoutKey(x, 'b')); // {a: 1, c: 3, z:26}
console.log(x); // {a: 1, b: 2, c: 3, z:26};

Demo in Babel REPL

Quelle:

Paul Kögel
quelle
3
Dies ist eine schöne Syntax.
Hinrich
2
Das ist großartig, aber gibt es eine Möglichkeit, den nicht verwendeten var deletedKey zu vermeiden? Nicht, dass es irgendwelche Probleme verursacht, aber JSHint beschwert sich und scheint seltsam, da wir es wirklich nicht verwenden.
Johnson Wong
6
@JohnsonWong Wie wäre es mit _der Verwendung einer Variablen, die Sie nicht verwenden möchten ?
Ryan H.
var b = {a:44, b:7, c:1}; let {['a']:z, ...others} = b; console.log(z , others ); // logs: 44, {b:7, c:1}
Jimmy
70

Für diejenigen, die ES6 nicht verwenden können, können Sie lodashoder verwenden underscore.

_.omit(x, 'b')

Oder ramda.

R.omit('b', x)
Noel Llevares
quelle
6
wäre es nicht logisch, verwenden auslassen hier? _.omit(x, 'b')
Tibalt
Danke @tibalt. Aktualisierte die Antwort damit.
Noel Llevares
Löschen ist prägnanter - die Verwendung von lodash, Unterstrich oder Ramda ist nur für Projekte relevant, die sie bereits verwenden und kennen, andernfalls ist dies ab 2018 zunehmend irrelevant.
Jimmy
1
@jimmont delete wird bereits in anderen Antworten erwähnt. Es sind keine doppelten Antworten erforderlich, finden Sie nicht? Und natürlich ist es nur für diejenigen relevant, die bereits Lodash oder Ramda verwenden. Und es ist auch nur für diejenigen relevant, die mit ES5 und früher stecken, wie in dieser Antwort angegeben.
Noel Llevares
@dashmug Mein vorheriger Kommentar war eine Kritik des Ansatzes (nicht Ihrer Antwort), die bei der Auswahl des in dieser Antwort dargestellten Ansatzes beachtet werden sollte. Ich möchte diese Informationen, wenn ich die Antworten durchgelesen habe, und ist der Grund, meinen Kommentar hinzuzufügen und zu erwähnen delete.
Jimmy
63

Ich benutze diesen ESNext One Liner

const obj = { a: 1, b: 2, c: 3, d: 4 }
const clone = (({ b, c, ...o }) => o)(obj) // remove b and c
console.log(clone)


Wenn Sie eine Allzweckfunktion benötigen:

function omit(obj, props) {
  props = props instanceof Array ? props : [props]
  return eval(`(({${props.join(',')}, ...o}) => o)(obj)`)
}

// usage
const obj = { a: 1, b: 2, c: 3, d: 4 }
const clone = omit(obj, ['b', 'c'])
console.log(clone)

vdegenne
quelle
9
Anstatt in Array zu wickeln und mapSie können tun:(({b, c, ...others}) => ({...others}))(obj)
Bucabay
@bucabay: Genial! Das ist die beste Antwort! Standardkonform, funktioniert perfekt in Node usw. Sie sollten als Antwort einreichen.
david.pfx
3
Fantastische Antwort Kumpel .. <3
Ajithkumar S
5
@totymedli: Nicht von mir. Ich werde die syntaktische Form, Teil von Standard ES6, aus Gründen der Lesbarkeit jederzeit über eine magische Funktion übernehmen.
david.pfx
1
Brillant. Das ist alles.
Darksoulsong
22

Sie können eine einfache Hilfsfunktion dafür schreiben. Lodash hat eine ähnliche Funktion mit dem gleichen Namen: weglassen

function omit(obj, omitKey) {
  return Object.keys(obj).reduce((result, key) => {
    if(key !== omitKey) {
       result[key] = obj[key];
    }
    return result;
  }, {});
}

omit({a: 1, b: 2, c: 3}, 'c')  // {a: 1, b: 2}

Beachten Sie außerdem, dass es schneller als Object.assign ist und löschen Sie dann: http://jsperf.com/omit-key

Just-Boris
quelle
11

Vielleicht so etwas:

var copy = Object.assign({}, {a: 1, b: 2, c: 3})
delete copy.c;

Ist das gut genug Oder kann man nicht ckopieren?

clean_coding
quelle
11

Verwenden der Objektzerstörung

const omit = (prop, { [prop]: _, ...rest }) => rest;
const obj = { a: 1, b: 2, c: 3 };
const objWithoutA = omit('a', obj);
console.log(objWithoutA); // {b: 2, c: 3}

Ivan Nosov
quelle
Tolle Lösung!
Denys Mikhalenko
2
Ich denke, diese Lösung soll die Warnung "Nicht verwendete Variable" in JSLint verhindern. Leider _löst die Verwendung das Problem für ESLint nicht ...
Bert Bruynooghe
6

Hey, es scheint, als würden Sie auf Referenzprobleme stoßen, wenn Sie versuchen, ein Objekt zu kopieren und dann eine Eigenschaft zu löschen. Irgendwo müssen Sie primitive Variablen zuweisen, damit Javascript einen neuen Wert erzeugt.

Einfacher Trick (kann schrecklich sein), den ich benutzt habe, war dieser

var obj = {"key1":"value1","key2":"value2","key3":"value3"};

// assign it as a new variable for javascript to cache
var copy = JSON.stringify(obj);
// reconstitute as an object
copy = JSON.parse(copy);
// now you can safely run delete on the copy with completely new values
delete copy.key2

console.log(obj)
// output: {key1: "value1", key2: "value2", key3: "value3"}
console.log(copy)
// output: {key1: "value1", key3: "value3"}
Chris Fust
quelle
Eigentlich mag ich es irgendwie. Könnte tun JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Sie müssen es nicht einmal löschen, sondern benötigen nur einen falschen Wert.
Tschad
6

Hier ist eine Option zum Weglassen dynamischer Schlüssel, von denen ich glaube, dass sie noch nicht erwähnt wurden:

const obj = { 1: 1, 2: 2, 3: 3, 4: 4 };
const removeMe = 1;

const { [removeMe]: removedKey, ...newObj } = obj;

removeMewird als voreingenommen removedKeyund ignoriert. newObjwird { 2: 2, 3: 3, 4: 4 }. Beachten Sie, dass der entfernte Schlüssel nicht vorhanden ist und der Wert nicht nur auf gesetzt wurde undefined.

Goldins
quelle
Schöne Lösung. Ich hatte einen ähnlichen Anwendungsfall (dynamischer Schlüssel im Reduzierer).
Ericgio
4

EINFACHSTER WEG

const allAlphabets = {a: 1, b: 2, c: 3, ..., z:26};
const { b, ...allExceptOne } = allAlphabets;
console.log(allExceptOne);   // {a: 1, c: 3, ..., z:26}
Android Ocean
quelle
3

Lodash weglassen

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}
OscarRyz
quelle
Ja, Lodash ist eine elegante Option, aber ich habe versucht, dasselbe mit Vanille ES6 zu erreichen
andreasonny83
3

Sie können dazu auch den Spread-Operator verwenden

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }
Mickael M.
quelle
2
Scheint super geschickt. Dies hält jedoch den Schlüssel als undefiniert incopy
Kano
Sie können also die undefinierten Schlüssel entfernen, wenn die einzigen vorhanden sind
Victor
1
Ich bin mir nicht sicher, warum Sie die zusätzliche Verbreitung in der Kopie vorgenommen haben, const copy = { ...source, b: undefined } läuft genau auf das Gleiche hinaus.
Bert Bruynooghe
3

Die oben genannten Lösungen mit Strukturierung leiden unter der Tatsache, dass Sie eine verwendete Variable haben, was zu Beschwerden von ESLint führen kann, wenn Sie diese verwenden.

Also hier sind meine Lösungen:

const src = { a: 1, b: 2 }
const result = Object.keys(src)
  .reduce((acc, k) => k === 'b' ? acc : { ...acc, [k]: src[k] }, {})

Auf den meisten Plattformen (außer IE, sofern nicht Babel verwendet wird) können Sie außerdem Folgendes tun:

const src = { a: 1, b: 2 }
const result = Object.fromEntries(
  Object.entries(src).filter(k => k !== 'b'))
Bert Bruynooghe
quelle
3

Wie wäre es damit:

let clone = Object.assign({}, value);
delete clone.unwantedKey;
Lars Juel Jensen
quelle
2

Wenn Sie mit einer großen Variablen arbeiten, möchten Sie sie nicht kopieren und dann löschen, da dies ineffizient wäre.

Eine einfache for-Schleife mit einer hasOwnProperty-Prüfung sollte funktionieren und ist viel anpassungsfähiger für zukünftige Anforderungen:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}
HoldOffHunger
quelle
1
Die Spread-Operator-Lösung macht genau das Gleiche mit einer weitaus schöneren Syntax.
david.pfx
2

Was ist damit? Ich habe dieses Muster nie gefunden, aber ich habe nur versucht, eine oder mehrere Eigenschaften auszuschließen, ohne ein zusätzliches Objekt erstellen zu müssen. Dies scheint den Job zu erledigen, aber es gibt einige Nebenwirkungen, die ich nicht sehen kann. Sicher ist nicht sehr lesbar.

const postData = {
   token: 'secret-token',
   publicKey: 'public is safe',
   somethingElse: true,
};

const a = {
   ...(({token, ...rest} = postData) => (rest))(),
}

/**
a: {
   publicKey: 'public is safe',
   somethingElse: true,
}
*/
andreasonny83
quelle
2

Ich habe es so gemacht, als Beispiel von meinem Redux-Reduzierer:

 const clone = { ...state };
 delete clone[action.id];
 return clone;

Mit anderen Worten:

const clone = { ...originalObject } // note: original object is not altered
delete clone[unwantedKey]           // or use clone.unwantedKey or any other applicable syntax
return clone                        // the original object without the unwanted key
Jonathan Tuzman
quelle
Scheint viel zusätzliche Arbeit zu sein, verglichen mit der akzeptierten Antwort von vor 3 Jahren (und beide Optionen hängen für viele Browser vom Transpilieren ab).
Carpiediem
Ich habe einen ähnlichen Anwendungsfall (Reduzierer), daher habe ich eine nette Methode gefunden, die dynamische Schlüssel ohne Mutation unterstützt. Grundsätzlich gilt: const { [removeMe]: removedKey, ...newObj } = obj;- siehe meine Antwort auf diese Frage.
Goldins
1

Ich habe es kürzlich ganz einfach gemacht:

const obj = {a: 1, b: 2, ..., z:26};

Verwenden Sie einfach den Spread-Operator , um die unerwünschte Eigenschaft zu trennen:

const {b, ...rest} = obj;

... und object.assign , um nur den ' Rest'-Teil zu übernehmen:

const newObj = Object.assign({}, {...rest});
Pepdbm 7
quelle
3
restist bereits ein neues Objekt - Sie brauchen nicht die letzte Zeile. Dies ist außerdem identisch mit der akzeptierten Lösung.
Carpiediem
0
const x = {obj1: 1, pass: 2, obj2: 3, obj3:26};

const objectWithoutKey = (object, key) => {
  const {[key]: deletedKey, ...otherKeys} = object;
  return otherKeys;
}

console.log(objectWithoutKey(x, 'pass'));
Ghiles Ybeggazene
quelle
1
Obwohl dieser Code eine Lösung für die Frage bietet, ist es besser, einen Kontext hinzuzufügen, warum / wie er funktioniert. Dies kann zukünftigen Benutzern helfen, zu lernen und dieses Wissen auf ihren eigenen Code anzuwenden. Es ist auch wahrscheinlich, dass Sie positive Rückmeldungen von Benutzern in Form von Upvotes erhalten, wenn der Code erklärt wird.
Borchvm