Comment puis-je cloner un objet JavaScript à l'exception d'une clé?

308

J'ai un objet JS plat:

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

Je veux cloner l'objet à l'exception d'un élément:

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

Quelle est la façon la plus simple de le faire (préférant utiliser es6 / 7 si possible)?

Renard
la source
Sans changer l'objet d'origine: JSON.parse (JSON.stringify ({... obj, 'key2': undefined}))
infinity1975

Réponses:

441

Si vous utilisez Babel, vous pouvez utiliser la syntaxe suivante pour copier la propriété b de x dans la variable b, puis copier le reste des propriétés dans la variable y :

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

et il sera transposé en:

"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
la source
58
Si vous peluchez votre code pour les variables inutilisées, cela se traduira par une "variable inutilisée 'b'". " avertissement cependant.
Ross Allen
1
à quoi ressemblerait la syntaxe si vous aviezlet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup
14
@RossAllen Une option a ignoreRestSiblingsété ajoutée dans la v3.15.0 (3 février 2017). Voir: commit c59a0ba
Ilya Palkin
4
@IlyaPalkin Intéressant. Cela semble un peu paresseux car cela ne change pas le fait qu'il y ait une bportée.
Ross Allen
2
Si vous obtenez l'échec de la construction du module: SyntaxError: jeton inattendu, vous devrez probablement ajouter le plugin de transformation de propagation babel rest. Voir babeljs.io/docs/plugins/transform-object-rest-spread
jsaven
133
var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

ou si vous acceptez que la propriété ne soit pas définie:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});
madox2
la source
7
La simple suppression de la propriété est un moyen clair et simple de le faire.
sshow
24
La mise en garde avec suppression est que ce n'est pas une opération immuable.
Javid Jamae
1
cela garde la clé
Fareed Alnamrouti
1
Mon commentaire a été écrit avant de modifier sa réponse et d'ajouter la déclaration de suppression
Fareed Alnamrouti
C'est exactement ce que je cherchais, mais un peu plus implémenté d'une manière légèrement différente: var cake = {... currentCake, requestorId: undefined};
abelito
73

Pour ajouter à la réponse d'Ilya Palkin: vous pouvez même supprimer dynamiquement des clés:

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

Démo dans Babel REPL

La source:

Paul Kögel
la source
3
Ceci est une belle syntaxe.
Hinrich
2
C'est très bien, mais existe-t-il un moyen d'éviter la var suppriméKey non utilisée? Non pas que cela cause des problèmes, mais fait se plaindre JSHint, et semble étrange car nous ne l'utilisons vraiment pas.
Johnson Wong
6
@JohnsonWong Que diriez-vous d'utiliser _ce qui est autorisé pour une variable que vous n'avez pas l'intention d'utiliser?
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

Pour ceux qui ne peuvent pas utiliser ES6, vous pouvez utiliser lodashou underscore.

_.omit(x, 'b')

Ou ramda.

R.omit('b', x)
Noel Llevares
la source
6
ne serait-il pas plus logique d'utiliser omit ici? _.omit(x, 'b')
tibalt
Merci @tibalt. Mis à jour la réponse avec.
Noel Llevares
supprimer est plus concis - l'utilisation de lodash, underscore ou ramda ne concerne que les projets qui les utilisent déjà et les connaissent, sinon cela est de plus en plus hors de propos en 2018 et au-delà.
jimmont
1
@jimmont delete est déjà mentionné dans d'autres réponses. Vous n'avez pas besoin de réponses en double, vous ne pensez pas? Et bien sûr, cela ne concerne que ceux qui utilisent déjà le lodash ou le ramda. Et cela n'est également pertinent que pour ceux qui sont bloqués avec ES5 et plus tôt, comme indiqué dans cette réponse.
Noel Llevares
@dashmug mon commentaire précédent était une critique de l'approche (pas de votre réponse) qui devrait être notée lors du choix d'utiliser l'approche représentée dans cette réponse. Je voudrais cette information si je lisais les réponses et c'est la raison pour ajouter mon commentaire et mentionner delete.
jimmont
63

J'utilise cette doublure ESNext one

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


Si vous avez besoin d'une fonction à usage général:

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
la source
9
Au lieu d'envelopper dans un tableau et mapvous pouvez faire:(({b, c, ...others}) => ({...others}))(obj)
bucabay
@bucabay: Brillant! C'est la meilleure réponse du lot! Conforme aux normes, fonctionne parfaitement dans Node etc. Vous devez soumettre une réponse.
david.pfx
3
Fantastic answer mate .. <3
Ajithkumar S
5
@totymedli: Pas par moi. Je prendrai la forme syntaxique, qui fait partie de la norme ES6, sur une fonction magique à tout moment, pour des raisons de lisibilité.
david.pfx
1
Brillant. C'est tout.
darksoulsong
22

Vous pouvez lui écrire une fonction d'assistance simple. Lodash a une fonction similaire avec le même nom: omettre

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}

Notez également qu'il est plus rapide que Object.assign et supprimez ensuite: http://jsperf.com/omit-key

just-boris
la source
11

Peut-être quelque chose comme ça:

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

Est-ce assez bon? Ou ne pouvez-vous pas créellement les copier?

clean_coding
la source
11

Utilisation de la déstructuration d'objets

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
la source
Excellente solution!
Denys Mikhalenko
2
Je suppose que cette solution est destinée à empêcher l'avertissement «Variable inutilisée» dans JSLint. Malheureusement, l'utilisation _ne résout pas le problème pour ESLint ...
bert bruynooghe
6

Hé, vous semblez rencontrer des problèmes lorsque vous essayez de copier un objet, puis de supprimer une propriété. Quelque part, vous devez attribuer des variables primitives afin que javascript crée une nouvelle valeur.

Truc simple (peut-être horrible) que j'ai utilisé était-ce

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
la source
En fait, je l'aime. Pourrait faire JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Vous n'avez même pas besoin de le supprimer, il suffit d'une valeur falsifiée.
Chad
6

Voici une option pour omettre les clés dynamiques qui, je crois, n'a pas encore été mentionnée:

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

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

removeMeest aliasé removedKeyet ignoré. newObjdevient { 2: 2, 3: 3, 4: 4 }. Notez que la clé supprimée n'existe pas, la valeur n'était pas simplement définie sur undefined.

Goldins
la source
Belle solution. J'ai eu un cas d'utilisation similaire (clé dynamique dans le réducteur).
ericgio
4

PLUS FACILE

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
la source
3

Lodash omettent

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}
OscarRyz
la source
oui, Lodash est une option élégante, mais j'essayais de faire la même chose avec vanilla ES6
andreasonny83
3

Vous pouvez également utiliser l'opérateur d'étalement pour ce faire

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }
Mickael M.
la source
2
Semble super astucieux. Cela garde cependant la clé non définie danscopy
kano
vous pouvez donc supprimer les clés non définies s'il y en a les seules
Victor
1
Je ne sais pas pourquoi vous avez fait l'étalement supplémentaire dans la copie, const copy = { ...source, b: undefined } se résume exactement à la même chose.
bert bruynooghe
3

Les solutions ci-dessus utilisant la structuration souffrent du fait que vous avez une variable utilisée, ce qui peut provoquer des plaintes d'ESLint si vous l'utilisez.

Voici donc mes solutions:

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

Sur la plupart des plateformes (sauf IE sauf si vous utilisez Babel), vous pouvez également faire:

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

Que dis-tu de ça:

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

Si vous avez affaire à une énorme variable, vous ne voulez pas la copier puis la supprimer, car cela serait inefficace.

Une simple boucle for avec un contrôle hasOwnProperty devrait fonctionner, et elle est beaucoup plus adaptable aux besoins futurs:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}
HoldOffHunger
la source
1
La solution d'opérateur d'étalement fait exactement la même chose avec une syntaxe beaucoup plus agréable.
david.pfx
2

Et ça? Je n'ai jamais trouvé ce bagout mais j'essayais simplement d'exclure une ou plusieurs propriétés sans avoir besoin de créer un objet supplémentaire. Cela semble faire l'affaire, mais il y a des effets secondaires que je ne peux pas voir. Pour sûr, ce n'est pas très lisible.

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
la source
2

Je l'ai fait de cette façon, comme un exemple de mon réducteur Redux:

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

En d'autres termes:

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
la source
Semble beaucoup de travail supplémentaire, par rapport à la réponse acceptée d'il y a 3 ans (et les deux options reposent sur le transpiling pour de nombreux navigateurs).
carpiediem
J'ai un cas d'utilisation similaire (réducteur), j'ai donc trouvé une belle façon de prendre en charge les clés dynamiques sans mutation. Fondamentalement: const { [removeMe]: removedKey, ...newObj } = obj;- voir ma réponse sur cette question.
goldins
1

Je l'ai fait récemment de cette manière très simple:

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

en utilisant simplement l' opérateur spread pour séparer la propriété indésirable:

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

... et object.assign pour ne prendre que la partie "reste":

const newObj = Object.assign({}, {...rest});
Pepdbm 7
la source
3
restest déjà un nouvel objet - vous n'avez pas besoin de la dernière ligne. De plus, cela est identique à la solution acceptée.
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
la source
1
Bien que ce code puisse fournir une solution à la question, il est préférable d'ajouter du contexte pour expliquer pourquoi / comment cela fonctionne. Cela peut aider les futurs utilisateurs à apprendre et à appliquer ces connaissances à leur propre code. Vous êtes également susceptible d'avoir des commentaires positifs des utilisateurs sous forme de votes positifs, lorsque le code est expliqué.
borchvm