여러 JavaScript 개체의 속성을 연결하는 방법


105

여러 JavaScript 개체 (연관 배열)를 "추가"하는 가장 좋은 방법을 찾고 있습니다.

예를 들면 다음과 같습니다.

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

계산하는 가장 좋은 방법은 무엇입니까?

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

3
시맨틱 메모 : [] 구문에도 불구하고, 그것들은 전혀 배열이 아닙니다. 주문은 실제로 보장되지 않습니다.
Álvaro González

1
ecma 표준에 따라 반복 순서가 보장되지 않습니다. 그러나 그것은 대부분의 브라우저에서 구현되는 방식입니다. (John Resig에서)이 동작은 ECMAScript 사양에 의해 명시 적으로 정의되지 않은 상태로 남아 있습니다. ECMA-262, 섹션 12.6.4 : 속성을 열거하는 메커니즘은 구현에 따라 다릅니다. 그러나 사양은 구현과 상당히 다릅니다. ECMAScript의 모든 최신 구현은 정의 된 순서대로 객체 속성을 반복합니다. 이 때문에 Chrome 팀은 이것을 버그로 간주하여 수정할 것입니다.
Juan Mendes

답변:


159

Object.assign()Javascript에서 기본적으로이를 달성하기 위해 ECMAscript 6이 도입 되었습니다.

Object.assign () 메소드는 대상체에 하나 이상의 소스 개체로부터 자신의 모든 열거 속성 값을 복사하는 데 사용된다. 대상 개체를 반환합니다.

Object.assign ()에 대한 MDN 문서

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.assign많은 최신 브라우저에서 지원 되지만 아직 전부는 아닙니다. BabelTraceur 와 같은 변환기 를 사용하여 이전 버전과 호환되는 ES5 JavaScript를 생성하십시오.


4
이것은 내가 말할 수있는 최고 중 하나입니다. 이제 E6이 대부분 사용되므로 Object.assign이 가장 좋은 답변입니다.
Vimalraj Selvam

6
병합해야하는 개체 수를 모르는 경우 배열에 있으므로 다음과 같이 병합 할 수 있습니다.Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
Jeanluca Scaljeri

1
Object.assign.apply객체 배열을 병합하는 데 사용 하는 대신 스프레드 연산자를 사용하는 것입니다.Object.assign( ...objects )
Spen

이 질문에 대한 답변으로 이미 포함 된 @Spen. 나는 그것을 여기에 복제하는 것의 이점을 보지 못했습니다.
filoxo

4 시간 후이 답변은 Angular 7에서 내 문제를 해결했습니다. 답변의 단순성과 정확성에 감사드립니다.
Gel

35

다음 $.extend과 같이 jquery를 사용할 수 있습니다 .

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 jQuery의 방법을 사용하지 않더라도 해당 코드를 사용하여 고유 한 (아마도 더 구체적인) 구현을 구성 할 수 있습니다.
tvanfosson

25
@Randal : jQuery를 사용하지 않는 완벽한 이유가 많이 있습니다.
Tim Down

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

34

이렇게해야합니다.

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

산출:

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

length각 호출에서 배열의 크기를 조회 하지 않습니까? 나는 글을 쓰는 데 너무 for (var i = 0, len = array.length; i < len; ++i)익숙해서 내가 왜 그것을 시작했는지 머릿속에서 기억할 수 없다.
tvanfosson

1
네, 맞습니다. 길이를 한 번 캐시하는 것이 더 나은 성능입니다. 그러나 인수 "배열"의 크기가 그다지 크지 않을 가능성이 높기 때문에이 경우에는 실제로 중요하지 않습니다.
jhurshman

1
아니요, IE6에서는 약간 제외됩니다. 길이 속성에 액세스하는 비용은 len 변수에 액세스하는 것과 같습니다.
Alsciende 2010 년

1
@Juan 나는 당신이 틀렸다고 생각하며 내 마음을 결정하기 위해 몇 가지 테스트를했습니다. 길이를 캐싱하는 것은 수년 동안 쓸모없는 최적화에 대한 쉬운 신화이며 코드를 (약간) 읽기 어렵게 만듭니다. 실제로 길이를 캐싱하면 브라우저 속도가 느려질 수 있습니다 (Safari).
Alsciende 2010 년

2
'for (p in ...'대신 'for (var p in ...')를 쓰는 것이 더 낫지 않습니까?
Hugo

24

ECMAScript 6에는 확산 구문이 있습니다. 이제 다음과 같이 할 수 있습니다.

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

Underscore 에는이를 수행하는 방법이 거의 없습니다.

1. _.extend (대상, * 소스)

의 속성을 모두 복사 소스가 받는 개체 대상 객체 및 반환 대상 개체를.

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

또는

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

2. _.defaults (객체, * 기본값)

기입 정의 의 속성 객체 로부터 값을 디폴트 객체 및 반환 개체를 .

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

또는

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

4

함수가 3 개의 인수로 제한되어야하는 이유는 무엇입니까? 또한 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

이제 Object.assign () 보다 짧은 구문을 사용하여 얕은 복제 (프로토 타입 제외) 또는 객체 병합이 가능합니다 .

객체 리터럴 에대한 스프레드 구문 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 }

확산 (...) 연산자많은 최신 브라우저 에서 지원 되지만 전부는 아닙니다.

따라서 Babel 과 같은 트랜스 파일러 를 사용하여 ECMAScript 2015+ 코드를 현재 및 이전 브라우저 또는 환경에서 이전 버전과 호환되는 JavaScript 버전으로 변환 하는 것이 좋습니다 .

다음은 Babel이 생성 하는 동등한 코드 입니다 .

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

이것은 허용되는 답변보다 훨씬 더 강력한 답변입니다. 감사!
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;
}

주의 : 이전 개체의 기존 속성을 덮어 씁니다.


2
이것은 결국 부작용이 있습니다 a === d. 괜찮을 수도 있고 아닐 수도 있습니다.
tvanfosson

2

객체에 대해 ES7 스프레드 연산자 를 사용하는 것은 쉽습니다. 브라우저 콘솔에서

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

1
좋은. 이 질문은 10 년이 넘었고 지금은 이러한 간단한 조작이 쉬워서 기쁩니다. 다른 사람의 대답을 보면 그다지 쉽지 않았습니다.
Vlad

그래서 제가 답을 남겼습니다. :)
Purkhalo Alex

2

객체의 동적 번호를 병합하려면, 우리는 사용할 수 있습니다 Object.assign확산 구문 .

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

위의 함수는 모든 속성을 새 개체로 병합하고 이후 개체의 속성이 이전 개체의 속성을 덮어 쓰는 새 개체로 병합합니다.

데모:

객체의 배열을 병합하려면 유사한 방법을 적용 할 수 있습니다.

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

데모:


1

아마도 가장 빠르고 효율적이며 일반적인 방법은 다음과 같습니다 (여러 개체를 병합하고 첫 번째 개체에 복사-> 할당 할 수도 있음).

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

또한 참조로 전달 된 첫 번째 개체를 수정할 수도 있습니다. 이것을 원하지 않지만 모든 속성을 포함하는 완전히 새로운 객체를 원하면 {}를 첫 번째 인수로 전달할 수 있습니다.

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

Combined_object와 object1은 모두 object1, object2, object3의 속성을 포함합니다.

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

이 경우 Combined_object는 object1, object2, object3의 속성을 포함하지만 object1은 수정되지 않습니다.

여기에서 확인하십시오 : https://jsfiddle.net/ppwovxey/1/

참고 : JavaScript 개체는 참조로 전달됩니다.


1

ES6 ++

문제는 다양한 추가하고 다른 하나의 물체를.

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

객체 인 여러 키가있는 하나의 객체가 있다고 가정 해 보겠습니다.

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

이것은 내가 찾은 해결책이었습니다 (여전히 foreach해야합니다 : /)

let objAll = {};

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

이렇게하면 모든 객체 키를 하나에 동적으로 추가 할 수 있습니다.

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

0

가장 간단 : 분산 연산자

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.