Como clonar um objeto JavaScript, exceto uma chave?

308

Eu tenho um objeto JS simples:

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

Eu quero clonar o objeto, exceto um elemento:

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

Qual é a maneira mais fácil de fazer isso (preferindo usar o es6 / 7, se possível)?

Raposa
fonte
Sem alterar o objeto original: JSON.parse (JSON.stringify ({... obj, 'key2': undefined}))
infinity1975

Respostas:

441

Se você usar Babel, poderá usar a seguinte sintaxe para copiar a propriedade b de x na variável be, em seguida, copiar o restante das propriedades na variável y :

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

e será transpilado para:

"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
fonte
58
Se você codificar seu código para variáveis ​​não utilizadas, isso resultará em uma "variável não utilizada 'b'". aviso embora.
Ross Allen
1
como seria a aparência de sintaxe se você tevelet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup
14
@RossAllen Há uma opção ignoreRestSiblingsque foi adicionada na v3.15.0 (3 de fevereiro de 2017). Veja: commit c59a0ba
Ilya Palkin
4
@IlyaPalkin Interesting. Parece um pouco preguiçoso, porque não muda o fato de que existe um bescopo.
Ross Allen
2
Se você estiver obtendo uma falha na compilação do módulo: SyntaxError: token inesperado, provavelmente precisará adicionar o plug-in babel rest spread transform. Veja babeljs.io/docs/plugins/transform-object-rest-spread
jsaven
133
var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

ou se você aceitar que a propriedade seja indefinida:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});
madox2
fonte
7
Simplesmente excluir a propriedade é uma maneira clara e simples de fazer isso.
Sshow 06/07/19
24
A ressalva com a exclusão é que não é uma operação imutável.
JavaScript é necessário
1
isso mantém a chave
Fareed Alnamrouti 27/1017
1
Meu comentário foi escrito antes de editar a sua resposta e adicione a instrução de exclusão
Fareed Alnamrouti
Era exatamente isso que eu estava procurando, mas um pouco mais implementado de uma maneira um pouco diferente: var cake = {... currentCake, requestorId: undefined};
Abelito 18/04/19
73

Para adicionar à resposta de Ilya Palkin: você pode remover dinamicamente as chaves:

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

Demonstração em Babel REPL

Fonte:

Paul Kögel
fonte
3
Essa é uma boa sintaxe.
Hinrich
2
Isso é ótimo, mas existe uma maneira de evitar a varkeyKey não usada? Não que esteja causando problemas, mas faz com que o JSHint se queixe, e parece estranho, pois realmente não o estamos usando.
Johnson Wong
6
@JohnsonWong Que tal usar o _que é permitido para uma variável que você não pretende usar?
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

Para aqueles que não podem usar o ES6, você pode usar lodashou underscore.

_.omit(x, 'b')

Or ramda.

R.omit('b', x)
Noel Llevares
fonte
6
não seria mais lógico usar omitir aqui? _.omit(x, 'b')
tibalt
Obrigado @tibalt. Atualizado a resposta com ele.
22617 Noel Llevares
delete é mais conciso - usar lodash, underscore ou ramda é relevante apenas para projetos que já os utilizam e os conhecem; caso contrário, isso é cada vez mais irrelevante em 2018 e além.
precisa saber é o seguinte
1
O @jimmont delete já foi mencionado em outras respostas. Não há necessidade de respostas duplicadas, você não acha? E, claro, isso é relevante apenas para aqueles que já usam lodash ou ramda. E isso também é relevante apenas para aqueles presos no ES5 e anteriores, conforme declarado nesta resposta.
Noel Llevares 10/09/18
@dashmug meu comentário anterior foi uma crítica à abordagem (não à sua resposta) que deve ser observada ao optar por usar a abordagem representada nesta resposta. Gostaria dessas informações se estivesse lendo as respostas e seja o motivo para adicionar meu comentário e menção delete.
Jimmont 19/09
63

Eu uso este forro 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)


Se você precisar de uma função de uso geral:

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
fonte
9
Em vez de agrupar em array, mapvocê pode:(({b, c, ...others}) => ({...others}))(obj)
bucabay 22/12
@bucabay: Brilhante! Essa é a melhor resposta do lote! Em conformidade com os padrões, funciona perfeitamente no Nó etc. Você deve enviar como resposta.
David.pfx
3
Resposta fantástica mate .. <3 #
Ajithkumar S
5
@totymedli: Não por mim. Eu assumirei a forma sintática, parte do padrão ES6, sobre uma função mágica a qualquer momento, por motivos de legibilidade.
David.pfx #
1
Brilhante. Isso é tudo.
darksoulsong
22

Você pode escrever uma função auxiliar simples para ela. Lodash tem uma função semelhante com o mesmo nome: omit

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}

Além disso, observe que é mais rápido que Object.assign e exclua: http://jsperf.com/omit-key

just-boris
fonte
11

Talvez algo parecido com isto:

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

Isso é bom o suficiente? Ou não pode crealmente ser copiado?

clean_coding
fonte
11

Usando a Reestruturação de Objetos

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
fonte
Ótima solução!
Denys Mikhalenko
2
Eu acho que essa solução tem como objetivo evitar o aviso 'Variável não utilizada' no JSLint. Infelizmente, usando _não resolve o problema para ESLint ...
bert bruynooghe
6

Ei, parece que você encontra problemas de referência quando tenta copiar um objeto e excluir uma propriedade. Em algum lugar você precisa atribuir variáveis ​​primitivas para que o javascript crie um novo valor.

Truque simples (pode ser horrível) eu usei foi este

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
fonte
Na verdade, eu até que gosto disso. Poderia fazer JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Nem precisa excluí-lo, apenas precisa de um valor falso.
Chad
6

Aqui está uma opção para omitir chaves dinâmicas que, acredito, ainda não foram mencionadas:

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

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

removeMeé alias removedKeye ignorado. newObjtorna-se { 2: 2, 3: 3, 4: 4 }. Observe que a chave removida não existe, o valor não foi apenas definido como undefined.

goldins
fonte
Ótima solução. Eu tive um caso de uso semelhante (chave dinâmica no redutor).
ericgio 04/12/19
4

CAMINHO MAIS FÁCIL

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
fonte
3

Omitir Lodash

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}
OscarRyz
fonte
sim, Lodash é uma opção elegante, mas eu estava tentando conseguir o mesmo com baunilha ES6
andreasonny83
3

Você também pode usar o operador spread para fazer isso

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }
Mickael M.
fonte
2
Parece super bacana. Este, porém, mantém a chave como indefinido nacopy
Kano
para que você possa remover as chaves indefinidas, se houver as únicas disponíveis lá #
Victor Victor
1
não sei por que você fez a propagação extra na cópia, const copy = { ...source, b: undefined } resume-se exatamente ao mesmo.
bert bruynooghe
3

As soluções acima usando a estruturação sofrem com o fato de você ter uma variável usada, o que pode causar reclamações do ESLint se você a estiver usando.

Então, aqui estão minhas soluções:

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

Na maioria das plataformas (exceto no IE, a menos que você use o Babel), você também pode:

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

Que tal agora:

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

Se você está lidando com uma variável enorme, não deseja copiá-la e excluí-la, pois isso seria ineficiente.

Um loop for simples com uma verificação hasOwnProperty deve funcionar e é muito mais adaptável às necessidades futuras:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}
HoldOffHunger
fonte
1
A solução do operador de propagação faz exatamente o mesmo com uma sintaxe muito melhor.
David.pfx
2

Que tal isso? Eu nunca encontrei esse padrão, mas estava apenas tentando excluir uma ou mais propriedades sem a necessidade de criar um objeto extra. Isso parece funcionar, mas existem alguns efeitos colaterais que não consigo ver. Com certeza não é muito legível.

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
fonte
2

Consegui dessa maneira, como um exemplo do meu redutor Redux:

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

Em outras palavras:

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
fonte
Parece muito trabalho extra, em comparação com a resposta aceita de três anos atrás (e as duas opções dependem da transpilação para muitos navegadores).
Carpiediem
Como tenho um caso de uso semelhante (redutor), criei uma boa maneira de oferecer suporte a chaves dinâmicas sem mutação. Basicamente: const { [removeMe]: removedKey, ...newObj } = obj;- veja minha resposta sobre esta pergunta.
goldins 2/10/19
1

Eu fiz recentemente dessa maneira muito simples:

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

apenas usando o operador spread para separar a propriedade indesejada:

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

... e object.assign para pegar apenas a parte 'rest':

const newObj = Object.assign({}, {...rest});
Pepdbm 7
fonte
3
restjá é um novo objeto - você não precisa da última linha. Além disso, isso é idêntico à solução aceita.
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
fonte
1
Embora esse código possa fornecer uma solução para a pergunta, é melhor adicionar contexto ao porquê / como ele funciona. Isso pode ajudar os usuários futuros a aprender e aplicar esse conhecimento ao seu próprio código. Também é provável que você tenha um feedback positivo dos usuários na forma de upvotes, quando o código for explicado.
borchvm