Come posso clonare un oggetto JavaScript ad eccezione di una chiave?


308

Ho un oggetto JS piatto:

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

Voglio clonare l'oggetto ad eccezione di un elemento:

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

Qual è il modo più semplice per farlo (preferendo usare es6 / 7 se possibile)?


Senza modificare l'oggetto originale: JSON.parse (JSON.stringify ({... obj, 'key2': undefined}))
infinity1975

Risposte:


441

Se usi Babel puoi usare la seguente sintassi per copiare la proprietà b da x nella variabile b e quindi copiare il resto delle proprietà nella variabile y :

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

e sarà traspilato 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"]);

58
Se lasci sfuggire il tuo codice per le variabili non utilizzate, questo si tradurrà in una "variabile non utilizzata" b ". avvertimento però.
Ross Allen,

1
come sarebbe la sintassi se tu avessilet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup

14
@RossAllen Esiste un'opzione ignoreRestSiblingsche è stata aggiunta in v3.15.0 (3 febbraio 2017). Vedi: commit c59a0ba
Ilya Palkin

4
@IlyaPalkin Interessante. Sembra un po 'pigro perché non cambia il fatto che esiste un bambito.
Ross Allen

2
Se stai ottenendo la compilazione del modulo non riuscita: SyntaxError: token imprevisto, probabilmente dovrai aggiungere il plug-in di trasformazione diffusione babel rest. Vedi babeljs.io/docs/plugins/transform-object-rest-spread
jsaven

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

o se si accetta che la proprietà non sia definita:

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

7
La semplice eliminazione della proprietà è un modo chiaro e semplice per farlo.
Mostra il

24
L'avvertenza con delete è che non è un'operazione immutabile.
Javid Jamae,

1
questo mantiene la chiave
Fareed Alnamrouti,

1
Il mio commento è stato scritto prima che modificasse la sua risposta e aggiungesse la dichiarazione di cancellazione
Fareed Alnamrouti,

Questo è esattamente quello che stavo cercando, ma un po 'più implementato in un modo leggermente diverso: var cake = {... currentCake, requestorId: undefined};
abelito,

73

Per aggiungere alla risposta di Ilya Palkin: puoi persino rimuovere dinamicamente le chiavi:

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

Fonte:


3
Questa è una bella sintassi.
Hinrich,

2
Questo è fantastico, ma c'è un modo per evitare la var cancellata inutilizzataKey? Non che stia causando problemi, ma fa lamentare JSHint e sembra strano dal momento che non lo stiamo davvero usando.
Johnson Wong,

6
@JohnsonWong Che ne dici di usare _quale è consentito per una variabile che non intendi utilizzare?
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}
Jimmont,

70

Per coloro che non possono utilizzare ES6, è possibile utilizzare lodasho underscore.

_.omit(x, 'b')

Or ramda.

R.omit('b', x)

6
non sarebbe più logico usare ometti qui? _.omit(x, 'b')
Tibet

Grazie @tibalt. Aggiornato la risposta con esso.
Noel Llevares,

l'eliminazione è più concisa: l'utilizzo di lodash, underscore o ramda è rilevante solo per i progetti che già li utilizzano e li conoscono, altrimenti è sempre più irrilevante nel 2018 e oltre.
Jimmont,

1
L'eliminazione di @jimmont è già menzionata in altre risposte. Non c'è bisogno di risposte duplicate, non credi? E, naturalmente, è rilevante solo per coloro che già usano lodash o ramda. Ed è anche rilevante solo per quelli bloccati con ES5 e precedenti, come indicato in questa risposta.
Noel Llevares,

@dashmug il mio commento precedente era una critica all'approccio (non alla tua risposta) che dovrebbe essere notato quando si sceglie di usare l'approccio rappresentato in questa risposta. Vorrei queste informazioni se stessi leggendo le risposte ed è la ragione per aggiungere il mio commento e menzionarlo delete.
Jimmont,

63

Uso questo ESLext 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)


Se hai bisogno di una funzione generica:

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)


9
Invece di avvolgere in array e mappuoi fare:(({b, c, ...others}) => ({...others}))(obj)
bucabay

@bucabay: geniale! Questa è la migliore risposta del lotto! Conforme agli standard, funziona perfettamente in Nodo ecc. È necessario inviare come risposta.
david.pfx,

3
Risposta fantastica
amico

5
@totymedli: non da parte mia. Prenderò la forma sintattica, parte dello standard ES6, su una funzione magica in qualsiasi momento, per motivi di leggibilità.
david.pfx,

1
Brillante. È tutto.
darksoulsong

22

Puoi scrivere una semplice funzione di supporto per questo. Lodash ha una funzione simile con lo stesso nome: ometti

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}

Inoltre, nota che è più veloce di Object.assign ed elimina quindi: http://jsperf.com/omit-key


11

Forse qualcosa del genere:

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

È abbastanza buono? O non puoi cdavvero copiarlo?


11

Utilizzo della distruzione degli oggetti

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}


Ottima soluzione!
Denys Mikhalenko,

2
Immagino che questa soluzione abbia lo scopo di prevenire l'avviso "Variabile non utilizzata" in JSLint. Sfortunatamente, l'utilizzo _non risolve il problema con ESLint ...
bert bruynooghe

6

Ehi sembra che ti imbatti in problemi di riferimento quando stai provando a copiare un oggetto e poi a eliminare una proprietà. Da qualche parte devi assegnare variabili primitive così javascript fa un nuovo valore.

Il trucco semplice (può essere orrendo) che ho usato era questo

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

In realtà mi piace. Potrebbe fare JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Non è nemmeno necessario eliminarlo, necessita solo di un valore errato.
Chad,

6

Ecco un'opzione per omettere i tasti dinamici che credo non sia ancora stata menzionata:

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

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

removeMeè aliasato removedKeye ignorato. newObjdiventa { 2: 2, 3: 3, 4: 4 }. Si noti che la chiave rimossa non esiste, il valore non è stato semplicemente impostato su undefined.


Bella soluzione. Ho avuto un caso d'uso simile (chiave dinamica nel riduttore).
ericgio,

4

MODO PIÙ SEMPLICE

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

3

Lodash omette

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}

sì, Lodash è un'opzione elegante, ma stavo cercando di ottenere lo stesso risultato con la vaniglia ES6
andreasonny83

3

Puoi anche usare l'operatore spread per fare questo

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }

2
Sembra super elegante. Ciò mantiene tuttavia la chiave indefinita incopy
kano,

in modo da poter rimuovere le chiavi indefinite se ce ne sono le uniche presenti
Victor

1
non so perché hai fatto la diffusione extra nella copia, const copy = { ...source, b: undefined } si riduce esattamente allo stesso.
bert bruynooghe,

3

Le soluzioni sopra usando la strutturazione soffrono del fatto che hai una variabile usata, che potrebbe causare lamentele da ESLint se la stai usando.

Quindi ecco le mie soluzioni:

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

Sulla maggior parte delle piattaforme (tranne IE a meno che non usi Babel), puoi anche fare:

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

3

Cosa ne pensi di questo:

let clone = Object.assign({}, value);
delete clone.unwantedKey;

2

Se hai a che fare con una variabile enorme, non vuoi copiarla e quindi eliminarla, poiché ciò sarebbe inefficiente.

Un semplice for-loop con un controllo hasOwnProperty dovrebbe funzionare ed è molto più adattabile alle esigenze future:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}

1
La soluzione di operatore di diffusione fa esattamente lo stesso con una sintassi molto più bella.
david.pfx,

2

Che dire di questo? Non ho mai trovato questo scalpiccio in giro, ma stavo solo cercando di escludere una o più proprietà senza la necessità di creare un oggetto in più. Questo sembra fare il lavoro ma ci sono alcuni effetti collaterali che non riesco a vedere. Di sicuro non è molto leggibile.

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

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

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

2

L'ho realizzato in questo modo, ad esempio dal mio riduttore Redux:

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

In altre parole:

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

Sembra un sacco di lavoro extra, rispetto alla risposta accettata da 3 anni fa (ed entrambe le opzioni si basano sulla traspilazione per molti browser).
carpiediem

Ho un caso d'uso (riduttore) simile, quindi ho trovato un modo piacevole che supporta i tasti dinamici senza mutazione. In sostanza: const { [removeMe]: removedKey, ...newObj } = obj;- vedi la mia risposta su questa domanda.
Goldins,

1

Di recente l'ho fatto in un modo molto semplice:

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

basta usare l' operatore spread per separare la proprietà indesiderata:

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

... e object.assign per prendere solo la parte 'resto':

const newObj = Object.assign({}, {...rest});

3
restè già un nuovo oggetto: non è necessaria l'ultima riga. Inoltre, questo è identico alla soluzione accettata.
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'));

1
Mentre questo codice può fornire una soluzione alla domanda, è meglio aggiungere un contesto sul perché / come funziona. Questo può aiutare gli utenti futuri a imparare e applicare tali conoscenze al proprio codice. È inoltre probabile che tu riceva un feedback positivo dagli utenti sotto forma di valutazioni, quando viene spiegato il codice.
Borchvm,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.