Como duplicar propriedades do objeto em outro objeto?

185

Dado o objeto:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

como posso copiar as propriedades dentro de outro objeto ( secondObject) como este:

var secondObject = {
    key1 : 'value1',
    key2 : 'value2',
    key3 : 'value3',
    key4 : 'value4'
};

usando uma referência ao firstObject? Algo assim:

var secondObject = {
    firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

(isso não funciona ... coloquei apenas para mostrar em grandes linhas como eu gostaria de estruturar o código).

É possível uma solução sem o uso de estruturas JavaScript?

Igor Popov
fonte
3
Respondida aqui: stackoverflow.com/questions/171251/…
Calvin
1
A questão é: você quer uma cópia superficial ou profunda? Se profundo, quão profundo?
21812 georg
5
FWIW, eles são chamados de "propriedades", não "atributos".
TJ Crowder
Aqui está algo realmente feio que funciona, no entanto (não é realmente recomendado! Apenas uma prova de conceito de uma linha):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
Ben Lee
@TJCrowder: Corrigi a pergunta ... obrigado.
Igor Popov

Respostas:

213
for(var k in firstObject) secondObject[k]=firstObject[k];
Michael Krelin - hacker
fonte
3
@ BenLee, o que você está perdendo aqui é que Igor mostrou o uso exato que ele tem para isso, o que hasOwnPropertyé inútil. Enquanto eu encontrar o seu indicador útil, considero a ideia de aplicar quaisquer regras de qualquer situação prejudicial e imprudente. Como todas estas práticas de desenvolvimento orientada para o padrão que estão acontecendo, por isso não é pessoal ...
Michael Krelin - hacker de
1
@ MichaelKrelin-hacker, o que você está perdendo aqui é que o StackOverflow não é apenas para o benefício do OP. É usado como referência para futuros visitantes que podem ter casos de uso ligeiramente diferentes, nos quais esse ponteiro pode ser útil.
Ben Lee
@ BenLee, eu não sou IgorPopov ;-) E não sendo o OP, eu já disse que acho o ponteiro útil e sua resposta também, é a parte "você realmente deve estar usando" que eu não gosto.
Michael Krelin - hacker de
23
Você omite um hasOwnProperty()teste e as coisas meio que continuam funcionando. Até que parem, porque seus objetos se tornaram mais complexos com o tempo. Exceto então, ele quebra misteriosamente em uma parte não relacionada do código porque muito foi copiado. E você não tem nenhum contexto para depuração. O JS é péssimo assim, por isso é prudente a codificação cuidadosa para evitar que esses problemas ocorram.
Eli Bendersky
2
Eu acho que essa resposta precisa ser atualizada conforme o link a seguir developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… const target = {a: 1, b: 2}; fonte const = {b: 4, c: 5}; const returnTarget = Object.assign (destino, origem); console.log (destino); // saída esperada: Objeto {a: 1, b: 4, c: 5} console.log (retornadoTarget); // saída esperada: Objeto {a: 1, b: 4, c: 5}
Elbassel 28/03/19
170

Tomando uma sugestão da resposta de @ Bardzuśny aqui, o ES6 forneceu uma solução nativa: a Object.assign()função!

O uso é simples:

Object.assign(secondObject, firstObject);

É isso aí!

O suporte agora é obviamente ruim; somente o Firefox (34+) é compatível imediatamente, enquanto o Chrome (45+) e o Opera (32+) exigem que o 'sinalizador experimental' seja definido.

O suporte está melhorando, com as versões mais recentes do Chrome, Firefox, Opera, Safari e Edge (o IE notavelmente não tem suporte). Transpilers também estão disponíveis, como Babel e Traceur. Veja aqui para mais detalhes.

O Ceifador DIMM
fonte
4
+1, outro recurso interessante do ES6. É claro que o suporte ao navegador / mesmo ao Node.JS está ausente por enquanto, mas como você mencionou, existem transpilers disponíveis. E se você não gosta deles - shims : github.com/paulmillr/es6-shim (ou autônomo, Object.assign()apenas shim: github.com/ljharb/object.assign ).
bardzusny
1
@Xoyce Se você verificar a página MDN vinculada, ela indicará claramente "Se o valor de origem for uma referência a um objeto, ele apenas copia esse valor de referência". Portanto, ele preserva a referência e não copia o objeto. Sua advertência contra comportamentos inesperados ainda é adequada, e tudo se resume a ter expectativas adequadas.
O DIMM Ceifador
@mostafiz Voltei sua edição, porque a pergunta e outras respostas nesta página usam os nomes "firstObject" e "secondObject", então usei os mesmos nomes aqui para maior clareza e consistência.
The DIMM Reaper
Se isso for consistente com a pergunta, tudo bem.
Mostafiz Rahman
1
@pdem Sim - veja a resposta do kingPuppy .
The DIMM Reaper
101

Por ES6 - sintaxe de propagação :

Você pode simplesmente usar:

const thirdObject = {
   ...firstObject,
   ...secondObject   
}

Isso evita problemas de passar esses objetos por referência.

Além disso, ele cuida de objetos com aninhamento profundo.

kingPuppy
fonte
2
Uau, isso é realmente incrível :) Obrigado pela resposta. Obviamente, não preciso mais dele (desde há um tempo), mas pode ajudar outra pessoa.
Igor Popov
1
+1 para um uso ainda mais bacana do ES6! Os docs MDN mencionado acima não mencionam usando o operador spread sobre os objetos, por isso fiz um violino para vê-lo em ação: es6fiddle.net/im3ifsg0
O DIMM Ceifador
1
@jaepage - bom comentário para referência. Um objeto (de acordo com a pergunta original) com nomes simples de propriedades é iterável.
kingPuppy
1
Funciona no Chrome, este é o ES6, você precisará do Babel ou de algum transpiler ES6 atualmente. No futuro, espera-se que todos os navegadores suportem esta sintaxe.
KingPuppy 14/05/19
89

Faça um loop pelas propriedades do primeiro objeto e atribua-as ao segundo objeto, assim:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

for (var prop in firstObject) {
    if (firstObject.hasOwnProperty(prop)) {
        secondObject[prop] = firstObject[prop];
    }
}

O loop for- innão é suficiente; você precisa hasOwnProperty. Veja http://bonsaiden.github.com/JavaScript-Garden/#object.forinloop para uma explicação detalhada do porquê.

Ben Lee
fonte
@ RobW, eu não acho que o OP esteja usando referenceno sentido técnico. Eu acho que ele apenas quer dizer "referência a" em linguagem natural.
21412 Ben Lee
1
@ RobW: O OP realmente disse "copiar".
TJ Crowder
49

Jogando o necromante aqui, porque o ES5 nos trouxe Object.keys(), com potencial para nos salvar de todas essas .hasOwnProperty()verificações.

Object.keys(firstObject).forEach(function(key) {
  secondObject[key] = firstObject[key];
});

Ou, agrupando-o em uma função ("cópia" limitada do lodash _.assign()):

function assign(object, source) {
  Object.keys(source).forEach(function(key) {
    object[key] = source[key];
  });
}

assign(secondObject, firstObject); // assign firstObject properties to secondObject

Object.keys()é um método relativamente novo, mais notavelmente: não disponível no IE <9. O mesmo vale para o .forEach()método array, que eu usei no lugar do forloop regular .

Felizmente, há es5-shim disponível para esses navegadores antigos, que preencherão muitos recursos do ES5 (incluindo os dois).

(Eu sou a favor de polyfills, em vez de não usar novos recursos interessantes de idioma.)

bardzusny
fonte
De repente, duas votações negativas do nada. Apostando com poucas chances de que esses caras leiam esse comentário - qual é a verdadeira razão para eles? Algo que você sugeriria mudar / melhorar na minha resposta?
bardzusny
1
Definitivamente, isso merece subir para o topo, assim como o inicializador de objetos mais para baixo (ES6) - isso parece ainda mais limpo com as funções de seta!
Mjohnsonengr 21/03
12

Necro'ing para que as pessoas possam encontrar um método de cópia profunda com hasOwnProperty e verificação de objeto real:

var extend = function (original, context, key) {
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        original[key] = extend(original[key] || {}, context[key]);
      else
        original[key] = context[key];
  return original;
};
Nijikokun
fonte
Observe que isso não copia em profundidade matrizes ou objetos de função (mas copia em profundidade todos os outros tipos de objetos).
Matt Browne
1
Sim, se você quiser matrizes cópia profunda que você acabou de modificar a verificação de tipo para incluir'[object Array]'
Nijikokun
12

Pode-se usar Object.assign para combinar objetos. Ele combinará e substituirá a propriedade comum da direita para a esquerda, ou seja, a mesma propriedade na esquerda será substituída pela direita.

E é importante fornecer um objeto vazio no primeiro para evitar a mutação dos objetos de origem. Os objetos de origem devem ser deixados limpos, pois, Object.assign()por si só, retorna um novo objeto.

Espero que isto ajude!

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

var finalObject = Object.assign({}, firstObject, secondObject)

console.log(finalObject)

Pranesh Ravi
fonte
mas e se você quiser alterar o primeiro objeto? Você tem o objeto A e o objeto B e deseja que ele mude o objeto A para que todas as propriedades sejam iguais às do objeto B? Você faria Object.assign (A, B)?
TKoL
Infelizmente, não há suporte para IE, Android WebView, Android Opera, de acordo com a página da Mozilla Developer Network.
precisa
6

Melhoria da ideia kingPuppy e OP (cópia superficial) - adiciono apenas 3 pontos ao "exemplo" do OP :)

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

Kamil Kiełczewski
fonte
4

Isso deve funcionar, testado aqui .

var secondObject = {
    firstObject: JSON.parse(JSON.stringify(firstObject)),
    key3 : 'value3',
    key4 : 'value4'
};

Nota : isso não copiará os métodos da firstObject
Nota 2 : para uso em navegadores antigos, você precisará de um analisador json
Nota 3 : atribuir por referência é uma opção viável, especialmente se firstObjectcontiver métodos. Ajustado o exemplo jsfiddle fornecido de acordo

KooiInc
fonte
3

Infelizmente, você não pode colocar uma referência a uma variável em um objeto como esse. No entanto, você pode criar uma função que copie os valores do objeto em outro objeto.

function extend( obj1, obj2 ) {
    for ( var i in obj2 ) {
        obj1[i] = obj2[i];
    }
    return obj1;
}

var firstObject = {
    key1: "value1",
    key2: "value2"
};

var secondObject = extend({
    key3: "value3",
    key4: "value4"
}, firstObject );
Vai
fonte
Isso também copiará propriedades nativas. E quanto às propriedades que são os próprios objetos?
KooiInc
1

Se você deseja capturar apenas as propriedades existentes no segundo objeto, pode usar Object.keysas propriedades do primeiro objeto, pode executar dois métodos:

A.) map para atribuir as propriedades do primeiro objeto ao segundo objeto usando efeitos colaterais:

var a = {a:100, b:9000, c:300};
var b = {b:-1};

Object.keys(a).map(function(key, index) {
    if (typeof b[key] !== 'undefined') {
        console.log(key);
        b[key] = a[key];    
    }
});

B.) ou reducepara criar um novo objeto e atribuí-lo ao segundo objeto. Esteja ciente de que esse método substitui outras propriedades que o segundo objeto pode ter antes daquilo que não corresponde ao primeiro objeto:

var a = {a:100, b:9000, c:300};
var b = {b:-1, d:-1}; // d will be gone

b = Object.keys(a).reduce(function(result, current) {
    if (typeof b[current] !== 'undefined') {
        result[current] = a[current];   
    }
    return result;
}, {});
apebeast
fonte
1

Use a notação de propriedade espalhada. Foi adicionado no ES2018 (o spread para arrays / iterables era anterior, ES2015), {... firstObject} espalha todas as propriedades enumeráveis ​​como propriedades discretas.

let secondObject = {
      ...firstObject,
      key3 : 'value3',
      key4 : 'value4'
    }
Anthony Awuley
fonte
por favor você pode dar algum contexto da sua resposta e por isso é resolver a questão em apreço
Tamir Klein
0

Prefiro usar firstObject como protótipo de secondObject e adicionar descritor de propriedades:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3", writable: true, configurable: true, enumerable: true},
      key4: {value: "value4", writable: true, configurable: true, enumerable: true}
      });

Certamente não é uma linha, mas oferece mais controle. Se você estiver interessado em descritores de propriedade, sugiro ler este artigo: http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 e a página MDN https: //developer.mozilla. org / pt-br / docs / Web / JavaScript / Referência / Global_Objects / Object / create

Você também pode atribuir valores e omitir os descritores e torná-lo um pouco mais curto:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3"}
      key4: {value: "value4"}
  });

Compatibilidade: ECMAScript 5, então IE9 +

Ahmet Cetin
fonte
0
var firstObject = {
     key1: "value1",
     key2: "value2"
};

var secondObject = {
     key3: "value3",
     key4: "value4"
     copy: function(firstObject){
           this.key1 = firstObject.key1;
           this.key2 = firstObject.key2;
     }
 };

O uso do método follwing copiará as propriedades

secondObject.copy(firstObject)

Eu sou muito novo em javascript, mas achei isso funcionando. Um pouco demais, eu acho, mas funciona.

Sindhu Tirth
fonte