Jak powielić właściwości obiektu w innym obiekcie?


185

Biorąc pod uwagę przedmiot:

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

jak mogę skopiować właściwości wewnątrz innego obiektu ( secondObject) takiego jak ten:

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

za pomocą odniesienia do firstObject? Coś takiego:

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

(to nie działa ... Położyłem to, aby pokazać dużymi liniami, jak chciałbym ustrukturyzować kod).

Czy rozwiązanie jest możliwe bez użycia ram JavaScript?



1
Pytanie brzmi: czy chcesz płytką czy głęboką kopię? Jeśli głęboko, to jak głęboko?
georg

5
FWIW, nazywane są „właściwościami”, a nie „atrybutami”.
TJ Crowder

Oto coś naprawdę brzydkiego, które jednak działa (niezalecane! Tylko jednokierunkowy dowód koncepcji):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
Ben Lee

@TJCrowder: Poprawiłem pytanie ... dzięki.
Igor Popov

Odpowiedzi:


213
for(var k in firstObject) secondObject[k]=firstObject[k];

3
@BenLee, brakuje Ci tutaj tego, że Igor pokazał, jak dokładnie do tego służy, w czym hasOwnPropertyjest bezużyteczny. Chociaż uważam, że twój wskaźnik jest przydatny, uważam, że pomysł zastosowania jakichkolwiek reguł w każdej sytuacji jest szkodliwy i nierozsądny. Podobnie jak wszystkie te praktyki projektowania oparte na wzorcach, które mają miejsce, więc nie bierz tego do siebie…
Michael Krelin - haker

1
@ MichaelKrelin-hacker, brakuje ci tutaj, że StackOverflow nie służy tylko PO. Jest wykorzystywany jako punkt odniesienia dla przyszłych użytkowników, którzy mogą mieć nieco inne przypadki użycia, w których ten wskaźnik może być przydatny.
Ben Lee,

@BenLee, nie jestem IgorPopov ;-) A ponieważ nie jestem OP, już powiedziałem, że uważam wskaźnik za przydatny i twoją odpowiedź też, to część „powinieneś naprawdę używać”, której nie lubię.
Michael Krelin - haker

23
Pomijasz hasOwnProperty()test i rzeczy nadal działają. Aż się zatrzymają, ponieważ twoje obiekty z czasem stały się bardziej złożone. Z wyjątkiem tego, że tajemniczo pęka w niepowiązanej części kodu, ponieważ zbyt wiele zostało skopiowanych. I nie masz żadnego kontekstu do debugowania. JS jest do bani, więc ostrożne kodowanie, aby zapobiec występowaniu takich problemów, jest rozsądne.
Eli Bendersky,

2
Myślę, że ta odpowiedź musi zostać zaktualizowana zgodnie z następującym linkiem developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… const target = {a: 1, b: 2}; const source = {b: 4, c: 5}; const returnTarget = Object.assign (cel, źródło); console.log (cel); // oczekiwany wynik: Object {a: 1, b: 4, c: 5} console.log (returnTarget); // oczekiwany wynik: Object {a: 1, b: 4, c: 5}
Elbassel

170

Biorąc pod uwagę odpowiedź @ Bardzuśny tutaj, ES6 dostarczył natywne rozwiązanie: Object.assign()funkcję!

Użycie jest proste:

Object.assign(secondObject, firstObject);

Otóż ​​to!

Wsparcie w tej chwili jest oczywiście słabe; tylko Firefox (34+) obsługuje go od razu po wyjęciu z pudełka, podczas gdy Chrome (45+) i Opera (32+) wymagają ustawienia „flagi eksperymentalnej”.

Wsparcie się poprawia, a najnowsze wersje Chrome, Firefox, Opera, Safari i Edge obsługują go (IE w szczególności nie obsługuje). Dostępne są również transpilery, takie jak Babel i Traceur. Zobacz tutaj po więcej szczegółów.


4
+1, kolejna fajna funkcja ES6. Oczywiście brakuje obsługi przeglądarki / nawet Node.JS, ale jak wspomniałeś, dostępne są transpilery. A jeśli ich nie lubisz - shims : github.com/paulmillr/es6-shim (lub samodzielny, Object.assign()-tylko shim : github.com/ljharb/object.assign ).
bardzusny

1
@Xoyce Jeśli sprawdzisz połączoną stronę MDN, wyraźnie powie: „Jeśli wartość źródłowa jest odwołaniem do obiektu, kopiuje tylko tę wartość odniesienia”. Tak więc rzeczywiście zachowuje odwołanie i nie kopiuje obiektu. Twoje ostrzeżenie przed nieoczekiwanym zachowaniem jest nadal trafne i sprowadza się do posiadania odpowiednich oczekiwań.
DIMM Reaper

@mostafiz Cofnąłem twoją edycję, ponieważ pytania i inne odpowiedzi na tej stronie używają nazw „firstObject” i „secondObject”, więc użyłem tutaj tych samych nazw dla jasności i spójności.
DIMM Reaper

Jeśli jest to zgodne z pytaniem, to jest w porządku.
Mostafiz Rahman

1
@pdem Tak - patrz odpowiedź kingPuppy .
DIMM Reaper

101

Na ES6 - Składnia spreadu :

Możesz po prostu użyć:

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

Pozwala to uniknąć problemów z przekazywaniem tych obiektów przez odniesienie.

Dodatkowo dba o obiekty, które mają głębokie zagnieżdżenie.


2
Wow, to jest naprawdę niesamowite :) Dzięki za odpowiedź. Oczywiście już go nie potrzebuję (ponieważ to było dawno temu), ale może pomóc komuś innemu.
Igor Popov

1
+1 za jeszcze lepsze wykorzystanie ES6! Dokumenty MDN, o których mowa powyżej, nie wspominają o używaniu operatora rozkładania na obiektach, więc zrobiłem skrzypce, aby zobaczyć go w akcji: es6fiddle.net/im3ifsg0
The DIMM Reaper

1
@jaepage - dobry komentarz w celach informacyjnych. Obiekt (zgodnie z pierwotnym pytaniem) o prostych nazwach właściwości można iterować.
kingPuppy

1
Działa w Chrome, jest to ES6, obecnie potrzebujesz Babel lub jakiegoś transpilatora ES6. W przyszłości oczekuje się, że wszystkie przeglądarki będą obsługiwały tę składnię.
kingPuppy

89

Zapętlaj właściwości pierwszego obiektu i przypisz je do drugiego obiektu:

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

for- inpętli nie jest wystarczająco; trzeba hasOwnProperty. Zobacz http://bonsaiden.github.com/JavaScript-Garden/#object.forinloop, aby uzyskać szczegółowe wyjaśnienie dlaczego.


@RobW, nie sądziłem, że OP używa referencew sensie technicznym. Myślę, że on po prostu oznacza „odwołujący się” w języku naturalnym.
Ben Lee,

1
@RobW: OP faktycznie powiedział „kopiuj”.
TJ Crowder

49

Granie tutaj w nekromantę, ponieważ ES5 przyniosło nam Object.keys()możliwość ocalenia nas przed tymi wszystkimi .hasOwnProperty()czekami.

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

Lub, zawijanie go w funkcję (ograniczona „kopia” 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()jest stosunkowo nową metodą, w szczególności: niedostępną w IE <9. To samo dotyczy .forEach()metody tablicowej, której użyłem zamiast zwykłej forpętli.

Na szczęście dla tych starożytnych przeglądarek dostępna jest wersja es5-shim , która wypełni wiele funkcji ES5 (w tym tych dwóch).

(Jestem zwolennikiem wielu wypełniaczy, a nie powstrzymywania się od używania fajnych, nowych funkcji językowych.)


Nagle 2 głosy oddane znikąd. Stawiając na małą szansę, że ci goście przeczytają ten komentarz - jaki jest ich prawdziwy powód? Czy chciałbyś coś zmienić / poprawić w mojej odpowiedzi?
bardzusny

1
To zdecydowanie zasługuje na wzniesienie się na szczyt, a także inicjalizator rozproszenia obiektów w dół (ES6) - dzięki funkcjom strzałek wygląda jeszcze czystiej!
mjohnsonengr

12

Necro'ing, aby ludzie mogli znaleźć metodę głębokiego kopiowania z hasOwnProperty i sprawdzaniem rzeczywistych obiektów:

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

Zauważ, że to nie kopiuje głęboko tablic ani obiektów funkcyjnych (ale kopiuje głęboko wszystkie inne rodzaje obiektów).
Matt Browne,

1
Tak, jeśli chcesz głęboko kopiować tablice, po prostu zmodyfikuj sprawdzanie typu, aby uwzględnić'[object Array]'
Nijikokun

12

Można użyć Object.assign do łączenia obiektów. Połączy i zastąpi wspólną własność od prawej do lewej, tzn. Ta sama właściwość po lewej stronie zostanie zastąpiona przez prawą.

Ważne jest, aby najpierw podać pusty obiekt, aby uniknąć mutacji obiektów źródłowych. Obiekty źródłowe należy pozostawić czyste, ponieważ Object.assign()samo w sobie zwraca nowy obiekt.

Mam nadzieję że to pomoże!

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

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

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

console.log(finalObject)


ale co jeśli chcesz zmutować pierwszy obiekt? Masz obiekt A i obiekt B i chcesz, aby mutował obiekt A, aby wszystkie właściwości były równe temu, co znajdują się na obiekcie B? Czy zrobiłbyś Object.assign (A, B)?
TKoL

Niestety nie jest obsługiwany w IE, Android WebView, Android Opera zgodnie z tą stroną Mozilla Developer Network.
Yetti99

6

Ulepszenie pomysłu kingPuppy i pomysłu OP (płytka kopia) - dodaję tylko 3 kropki do „przykładu” OP :)

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


4

To powinno działać, przetestowane tutaj .

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

Uwaga : nie spowoduje to skopiowania metod uwagi firstObject
2 : do użycia w starszych przeglądarkach potrzebny jest parser json
Uwaga 3 : przypisywanie przez referencję jest realną opcją, szczególnie jeśli firstObjectzawiera metody. Odpowiednio dostosowałem podany przykład jsfiddle


3

Niestety nie można umieścić odwołania do zmiennej w takim obiekcie. Można jednak utworzyć funkcję, która kopiuje wartości obiektu do innego obiektu.

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

Spowoduje to również skopiowanie właściwości natywnych. A co z właściwościami, które same są obiektami?
KooiInc,

1

Jeśli chcesz pobrać tylko właściwości istniejące w drugim obiekcie, możesz użyć Object.keysdo przechwycenia właściwości pierwszego obiektu, możesz wykonać dwie metody:

A.), map aby przypisać właściwości pierwszego obiektu do drugiego obiektu za pomocą efektów ubocznych:

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.) lub reduceutworzyć nowy obiekt i przypisać go do drugiego obiektu. Należy pamiętać, że ta metoda zastępuje inne właściwości, które drugi obiekt mógł mieć wcześniej niż te, które nie pasowały do ​​pierwszego obiektu:

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;
}, {});

1

Użyj notacji rozprzestrzeniania się właściwości. Został on dodany w ES2018 (spread dla tablic / iterable był wcześniejszy, ES2015), {... firstObject} rozdziela wszystkie wyliczalne właściwości jako własności dyskretne.

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

czy możesz podać kontekst odpowiedzi i wyjaśnić, dlaczego rozwiązuje ona omawiane pytanie
Tamir Klein,

0

Wolałbym użyć firstObject jako prototypu SecondObject i dodać deskryptor właściwości:

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

Z pewnością nie jest to jedna linijka, ale daje większą kontrolę. Jeśli jesteś zainteresowany deskryptorami właściwości, sugeruję przeczytać ten artykuł: http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 oraz stronę MDN https: //developer.mozilla. org / en-US / docs / Web / JavaScript / Reference / Global_Objects / Object / create

Możesz także po prostu przypisać wartości i pominąć deskryptory i uczynić go nieco krótszym:

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

Kompatybilność: ECMAScript 5, więc IE9 +


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

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

Użycie metody podążania spowoduje skopiowanie właściwości

secondObject.copy(firstObject)

Jestem bardzo nowy w javascript, ale znalazłem, że działa. Chyba trochę za długo, ale działa.

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.