Jak łączyć właściwości z wielu obiektów JavaScript


105

Szukam najlepszego sposobu „dodawania” wielu obiektów JavaScript (tablice asocjacyjne).

Na przykład, biorąc pod uwagę:

a = { "one" : 1, "two" : 2 };
b = { "three" : 3 };
c = { "four" : 4, "five" : 5 };

jaki jest najlepszy sposób obliczenia:

{ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

3
Uwaga semantyczna: pomimo składni [] nie są one w ogóle tablicami. Zamówienie nie jest tak naprawdę gwarantowane.
— Álvaro González

1
Kolejność iteracji nie jest gwarantowana zgodnie ze standardami ECMA. Ale to sposób, w jaki jest implementowany w większości przeglądarek. (Od John Resig) To zachowanie jest jawnie nieokreślone w specyfikacji ECMAScript. W ECMA-262, sekcja 12.6.4: Mechanika wyliczania właściwości ... zależy od implementacji. Jednak specyfikacja różni się znacznie od implementacji. Wszystkie nowoczesne implementacje ECMAScript wykonują iterację po właściwościach obiektów w kolejności, w jakiej zostały zdefiniowane. Z tego powodu zespół Chrome uznał to za błąd i będzie go naprawiać.
— Juan Mendes,

Odpowiedzi:


159

ECMAscript 6 wprowadzono, Object.assign()aby osiągnąć to natywnie w Javascript.

Metoda Object . assign () służy do kopiowania wartości wszystkich wyliczalnych właściwości własnych z jednego lub większej liczby obiektów źródłowych do obiektu docelowego. Zwróci obiekt docelowy.

Dokumentacja MDN dotycząca Object. assign ()

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

Object.assignjest obsługiwany w wielu nowoczesnych przeglądarkach, ale jeszcze nie we wszystkich. Użyj transpilera, takiego jak Babel i Traceur, aby wygenerować kompatybilny wstecz ES5 JavaScript.


4
To jedno z najlepszych, jakie mogę powiedzieć. Ponieważ obecnie najczęściej używa się E6, najlepszą odpowiedzią jest Object. assign.
— Vimalraj Selvam

6
Jeśli nie wiesz, ile obiektów należy scalić, ponieważ znajdują się one w tablicy, możesz je scalić w następujący sposób:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
— Jeanluca Scaljeri

1
Alternatywą dla Object.assign.applyscalania tablicy obiektów jest użycie operatora spreadu:Object.assign( ...objects )
— Spen

@Spen, który jest już uwzględniony jako odpowiedź na to pytanie. Nie widziałem korzyści z powielania go tutaj.
— filoxo

po 4 godzinach ta odpowiedź rozwiązała mój problem w Angular 7. Dzięki za prostotę i dokładność odpowiedzi.
— Żel

35

Możesz użyć jquery w $.extendten sposób:

let a = { "one" : 1, "two" : 2 },
    b = { "three" : 3 },
    c = { "four" : 4, "five" : 5 };

let d = $.extend({}, a, b, c)

console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


+1 Nawet jeśli nie używasz metody jQuery, możesz użyć ich kodu, aby pomóc w skonstruowaniu własnej (być może bardziej szczegółowej) implementacji.
— tvanfosson

25
@Randal: Istnieje wiele dobrych powodów, dla których nie należy używać jQuery.
— Tim Down

3
Edycja:d = $.extend({},a,b,c);
— Bob Stein

34

To powinno wystarczyć:

function collect() {
  var ret = {};
  var len = arguments.length;
  for (var i = 0; i < len; i++) {
    for (p in arguments[i]) {
      if (arguments[i].hasOwnProperty(p)) {
        ret[p] = arguments[i][p];
      }
    }
  }
  return ret;
}

let a = { "one" : 1, "two" : 2 };
let b = { "three" : 3 };
let c = { "four" : 4, "five" : 5 };

let d = collect(a, b, c);
console.log(d);

Wynik:

{
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5
}

Nie lengthsprawdza rozmiaru tablicy przy każdym wywołaniu? Jestem tak przyzwyczajony do pisania, for (var i = 0, len = array.length; i < len; ++i)że nie mogę sobie przypomnieć, dlaczego zacząłem to robić.
— tvanfosson

1
Tak, to jest poprawne. Lepszą wydajnością jest jednorazowe buforowanie długości. Ponieważ jednak rozmiar „tablicy” argumentów prawdopodobnie nigdy nie będzie bardzo duży, w tym przypadku nie będzie to miało większego znaczenia.
— jhurshman

1
Nie, z wyjątkiem nieznacznie w IE6. Dostęp do właściwości length kosztuje tyle samo, co dostęp do zmiennej len.
— Alsciende

1
@Juan Uważam, że się mylisz i zrobiłem kilka testów, aby się zdecydować. Buforowanie długości to łatwy mit optymalizacji, który był przestarzały przez wiele lat i sprawia, że ​​kod jest (nieco) mniej czytelny. W rzeczywistości buforowanie długości czasami spowalnia przeglądarkę (Safari).
— Alsciende

2
Czy nie byłoby lepiej napisać 'for (var p in ...' zamiast 'for (p in ...'?
— Hugo

24

ECMAScript 6 ma rozszerzoną składnię . A teraz możesz to zrobić:

const obj1 = { 1: 11, 2: 22 };
const obj2 = { 3: 33, 4: 44 };
const obj3 = { ...obj1, ...obj2 };

console.log(obj3); // {1: 11, 2: 22, 3: 33, 4: 44}


12

Podkreślenie ma kilka metod, aby to zrobić;

1. _.extend (miejsce docelowe, * źródła)

Skopiuj wszystkie właściwości obiektów źródłowych do obiektu docelowego i zwróć obiekt docelowy .

_.extend(a, _.extend(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Lub

_.extend(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.extend(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

2. _.defaults (obiekt, * domyślne)

Wypełnij niezdefiniowane właściwości obiektu wartościami z obiektów domyślnych i zwróć obiekt .

_.defaults(a, _.defaults(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Lub

_.defaults(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.defaults(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

4

Dlaczego funkcja powinna być ograniczona do 3 argumentów? Sprawdź także hasOwnProperty.

function Collect() {
    var o={};
    for(var i=0;i<arguments.length;i++) {
      var arg=arguments[i];
      if(typeof arg != "object") continue;
      for(var p in arg) {
        if(arg.hasOwnProperty(p)) o[p] = arg[p];
      }
    }
    return o;
}

4

Płytkie klonowanie (z wyłączeniem prototypu) lub scalanie obiektów jest teraz możliwe przy użyciu krótszej składni niż Object. assign () .

Składnia spreadów dla literałów obiektowych została wprowadzona w ECMAScript 2018 ):

const a = { "one": 1, "two": 2 };
const b = { "three": 3 };
const c = { "four": 4, "five": 5 };

const result = {...a, ...b, ...c};
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

Operator Spread (...) jest obsługiwany w wielu nowoczesnych przeglądarkach, ale nie we wszystkich.

Dlatego zaleca się użycie transpilera, takiego jak Babel, do konwersji kodu ECMAScript 2015+ na wsteczną kompatybilną wersję JavaScript w obecnych i starszych przeglądarkach lub środowiskach.

Oto równoważny kod, który Babel wygeneruje dla Ciebie:

"use strict";

var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        target[key] = source[key];
      }
    }
  }
  return target;
};

var a = { "one": 1, "two": 2 };
var b = { "three": 3 };
var c = { "four": 4, "five": 5 };

var result = _extends({}, a, b, c);
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

To jest znacznie bardziej solidna odpowiedź niż zaakceptowana odpowiedź. Dzięki!
— Kaleb Anderson

3
function Collect(a, b, c) {
    for (property in b)
        a[property] = b[property];

    for (property in c)
        a[property] = c[property];

    return a;
}

Uwaga: Istniejące właściwości w poprzednich obiektach zostaną nadpisane.


2
Ma to efekt uboczny, który a === dna końcu. To może być w porządku, a może nie.
— tvanfosson

3

Jest to łatwe przy użyciu operatora rozszerzania ES7 dla obiektu, w konsoli przeglądarki

({ name: "Alex", ...(true  ? { age: 19 } : { })}) // {name: "Alex", age: 19}
({ name: "Alex", ...(false ? { age: 19 } : { })}) // {name: "Alex",        }

1
Miły. To pytanie ma ponad 10 lat, cieszę się, że tak prosta obsługa jest teraz łatwa. Wcześniej nie było to takie łatwe, jeśli spojrzeć na odpowiedzi innych osób.
— Vlad

dlatego zostawiłem własną odpowiedź :)
— Purkhalo Alex

2

Aby scalić kilka dynamicznych obiektów, możemy skorzystać Object.assignze składni spread .

const mergeObjs = (...objs) => Object.assign({}, ...objs);

Powyższa funkcja akceptuje dowolną liczbę obiektów, łącząc wszystkie ich właściwości w nowy obiekt z właściwościami z późniejszych obiektów nadpisując te z poprzednich obiektów.

Próbny:

Aby połączyć tablicę obiektów, można zastosować podobną metodę.

const mergeArrayOfObjs = arr => Object.assign({}, ...arr);

Próbny:


1

Prawdopodobnie najszybszym, wydajnym i bardziej ogólnym sposobem jest to (możesz scalić dowolną liczbę obiektów, a nawet skopiować do pierwszego -> przypisz):

function object_merge(){
    for (var i=1; i<arguments.length; i++)
       for (var a in arguments[i])
         arguments[0][a] = arguments[i][a];
   return arguments[0];
}

Pozwala także na modyfikację pierwszego obiektu, który jest przekazywany przez odniesienie. Jeśli nie chcesz tego, ale chcesz mieć zupełnie nowy obiekt zawierający wszystkie właściwości, możesz przekazać {} jako pierwszy argument.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge(object1,object2,object3); 

Połączony_obiekt i obiekt1 zawierają właściwości obiekt1, obiekt2, obiekt3.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge({},object1,object2,object3); 

W tym przypadku połączony_obiekt zawiera właściwości obiektu1, obiekt2, obiekt3, ale obiekt1 nie jest modyfikowany.

Sprawdź tutaj: https://jsfiddle.net/ppwovxey/1/

Uwaga: obiekty JavaScript są przekazywane przez odniesienie.


1

ES6 ++

Pytanie jest dodawanie różnych różnych obiektów w jeden.

let obj = {};
const obj1 = { foo: 'bar' };
const obj2 = { bar: 'foo' };
Object.assign(obj, obj1, obj2);
//output => {foo: 'bar', bar: 'foo'};

powiedzmy, że masz jeden obiekt z wieloma kluczami, które są obiektami:

let obj = {
  foo: { bar: 'foo' },
  bar: { foo: 'bar' }
}

to było rozwiązanie, które znalazłem (nadal muszę na zawsze: /)

let objAll = {};

Object.values(obj).forEach(o => {
  objAll = {...objAll, ...o};
});

W ten sposób możemy dynamicznie dodawać WSZYSTKIE klucze obiektów do jednego.

// Output => { bar: 'foo', foo: 'bar' }

0

Najprostsze: operatory rozproszenia

var obj1 = {a: 1}
var obj2 = {b: 2}
var concat = { ...obj1, ...obj2 } // { a: 1, b: 2 }

-2
function collect(a, b, c){
    var d = {};

    for(p in a){
        d[p] = a[p];
    }
    for(p in b){
        d[p] = b[p];
    }
    for(p in c){
        d[p] = c[p];
    }

    return d;
}
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.