Jak połączyć ze sobą dwa obiekty javascript w ES6 +?


141

Mam dość ciągłego pisania kodu w ten sposób:

function shallowExtend(obj1,obj2){
  var key;
  for ( key in obj2 ) {
    if ( obj2.hasOwnProperty(key) === false )  continue;
    obj1[key] = obj2[key]
  }
}

Lub jeśli nie chcę sam pisać kodu, zaimplementuj bibliotekę, która już to robi. Z pewnością ES6 + przybywa na ratunek, a to zapewni nam coś w rodzajuObject.prototype.extend(obj2...) lubObject.extend(obj1,obj2...)

Czy więc ES6 + zapewnia taką funkcjonalność? Jeśli jeszcze go tam nie ma, to czy jest planowana taka funkcjonalność? Jeśli nie zaplanowano, dlaczego nie?


3
Dlaczego więc nie dodałeś go do swojej biblioteki?
— RobG,

12
@RobG to pytanie jest o nadziei, że ES6 usunie nas z konieczności trzeba taką szablonowe bzdura w pierwszym place.For co warto: github.com/balupton/bal-util/blob/...
— balupton

Nie sądzę, że istnieje ogólny sposób kopiowania par nazwa / wartość z jednego obiektu do drugiego. Czy zajmujesz się tylko własnymi nieruchomościami lub tymi w [[Prototype]]sieci? Robisz „głębokie” czy „płytkie” kopie? A co z właściwościami, których nie można wyliczyć i nie można zapisać? Myślę, że wolałbym mieć małą funkcję biblioteczną, która robi to, czego potrzebuję, a w większości przypadków i tak można jej uniknąć.
— RobG,

Odpowiedzi:


206

Będziesz mógł wykonać płytkie scalanie / rozszerzanie / przypisywanie w ES6 za pomocą Object. assign:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/ assign

Składnia:

Object. assign ( cel , źródła );

gdzie ... źródła reprezentują obiekty źródłowe.

Przykład:

var obj1 = {name: 'Daisy', age: 30};
var obj2 = {name: 'Casey'};

Object.assign(obj1, obj2);

console.log(obj1.name === 'Casey' && obj1.age === 30);
// true

64
Mała uwaga: Object. assign mutuje cel. Jeśli nie tego chcesz, możesz to nazwać pustym obiektem:let merged = Object.assign({}, source1, source2);
— david

20
Proszę zauważyć, że jest to płytkie rozszerzenie ... obiekty zagnieżdżone NIE są scalane
— monzonj

@monzonj, czy nie ma możliwości rozszerzania obiektów zagnieżdżonych bez użycia lodash lub mout?
— Joao Falcao

1
Istnieje dobry sposób na scalenie głęboko zagnieżdżonych obiektów bez biblioteki, używając tylko Object.assign: zobacz moją odpowiedź tutaj
— Ruslan

Stary sposób rozszerzania obiektów zagnieżdżonych to użycieJSON.parse(JSON.stringify(src))
— Andre Figueiredo

162

Możesz użyć do tego składni rozszerzania obiektów :

const merged = {...obj1, ...obj2}

W przypadku tablic operator rozprzestrzeniania był już częścią ES6 (ES2015), ale dla obiektów został dodany do specyfikacji języka w ES9 (ES2018). Jego propozycja została domyślnie włączona w narzędziach takich jak Babel dużo wcześniej.


3
Nie, oficjalnie nazywa się teraz ES2015: P Od kiedy destrukturyzacja nie jest częścią ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Uruchamianie węzła babel: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) Wyjście:{ foo: 123, bar: 234 }
— Thijs Koerselman

9
To nie jest destrukcja, rozprzestrzenia się - i nie, w przypadku obiektów nie jest to część ES6. Powinieneś wyłączyć eksperymentalne wersje robocze ES7 w swoim Babel.
— Bergi

2
Ach, wybacz mi. Masz rację. W tej chwili jest to funkcja Babel Stage 2. github.com/sebmarkbage/ecmascript-rest-spread Nigdy nie zdawałem sobie z tego sprawy, ponieważ używam go od początku z babel i jest domyślnie włączony. Ale ponieważ i tak musisz przetransponować, a rozprzestrzenianie się obiektu jest dość prostą rzeczą, i tak poleciłbym to. Kocham to.
— Thijs Koerselman

Są domyślnie włączone, naprawdę? To brzmi jak błąd.
— Bergi

2
„Propozycje na poziomie 2 lub wyższym są domyślnie włączone”. babeljs.io/docs/usage/experimental
— Thijs Koerselman

14

Wiem, że to trochę stary problem, ale najłatwiejsze rozwiązanie w ES2015 / ES6 jest w rzeczywistości dość proste, używając Object. assign (),

Miejmy nadzieję, że to pomoże, ale to również robi głębokie scalanie:

/**
 * Simple is object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}

/**
 * Deep merge two objects.
 * @param target
 * @param source
 */
export function mergeDeep(target, source) {
  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }
  return target;
}

Przykładowe użycie:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

7

Object.mixinObecnie omawiamy dodanie elementu , aby zadbać o zachowanie, o które prosisz. https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

Chociaż nie ma go jeszcze w wersji roboczej ES6, wydaje się, że jest dla niego duże poparcie, więc myślę, że wkrótce pojawi się w wersjach roboczych.



5
Ostrzeżenie - ta odpowiedź nie jest już poprawna, zobacz odpowiedź Jacka, aby uzyskać prawidłowe i działające podejście.
— Benjamin Gruenbaum

Object.mixin został zastąpiony przez
— Object. assign

7

ES6

Object.assign(o1,o2) ; 
Object.assign({},o1,o2) ; //safe inheritance
var copy=Object.assign({},o1); // clone o1
//------Transform array of objects to one object---
var subjects_assess=[{maths:92},{phy:75},{sport:99}];
Object.assign(...subjects_assess); // {maths:92,phy:75,sport:99}

ES7 lub Babel

{...o1,...o2} // inheritance
 var copy= {...o1};

1
@FilipBartuzi to nie ES6, do którego utworzyłeś łącze. Ale w zasadzie robi odpowiednik _.extend () w lodash / underscore.
— Nostalg.io

5

Może Object.definePropertiesmetoda ES5 zadziała?

na przykład

var a = {name:'fred'};
var b = {age: {value: 37, writeable: true}};

Object.defineProperties(a, b);

alert(a.age); // 37

Dokumentacja MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperties


Uważaj jednak. W co najmniej jednej przeglądarce ma to wpływ na wydajność.
— Reuben Morais

1
Myślę, że najciekawsze jest to, że definePropertiesdefiniuje własne właściwości. Nie nadpisuje właściwości w [[prototype]]łańcuchu, zacienia je.
— RobG,

2
Dobra sugestia, choć tak naprawdę nie jest rozszerzeniem, ponieważ służy bardziej do definiowania, jak powinny zachowywać się właściwości ... Wykonanie prostego obiektu Object.defineProperties (obj1, obj2) spowodowałoby nieoczekiwane rezultaty.
— balupton

musiałby Object.getOwnPropertyDescriptorrównież użyć do ustawienia właściwości, gdy jest to wartość złożona, lub skopiujesz przez odniesienie.
— dmp
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.