JavaScript 개발을 하다 보면 서로 다른 두 객체의 속성을 하나로 합쳐 새로운 객체를 만들어야 하는 경우가 자주 있습니다. 이번 글에서는 두 객체를 병합하면서도 원본 객체는 그대로 유지하는 방법을 알아보겠습니다.
문제 상황
다음과 같이 두 개의 객체가 정의되어 있다고 가정해 보겠습니다.
const a = {
a: 1,
af: function() { console.log(this.a) },
};
const b = {
b: 2,
bf: function() { console.log(this.b) },
};여기서 우리가 작성해야 할 함수는 이 두 객체를 인자로 받아, 각 객체가 가진 모든 속성을 포함하는 새로운 객체를 반환하는 것입니다. 결과물은 아래와 같은 형태가 됩니다.
const output = {
a: 1,
af: function() { console.log(this.a) },
b: 2,
bf: function() { console.log(this.b) },
}중요한 점은 병합 과정에서 원본 객체인 a와 b는 변경되지 않고 그대로 유지되어야 한다는 것입니다.
extend 함수 구현
이 문제는 여러 개의 객체를 순회하며 속성을 하나씩 복사하는 방식으로 해결할 수 있습니다. 아래 코드는 가변 인자(arguments)를 활용해 두 개 이상의 객체도 처리할 수 있도록 작성된 extend 함수입니다.
const a = {
a: 1,
af: function() { console.log(this.a) },
};
const b = {
b: 2,
bf: function() { console.log(this.b) },
};
const extend = function(){
let i, j, res = (arguments[0] || {});
for (i = 1; i < arguments.length; i++) {
const x = arguments[i];
for (j in x) {
if (x.hasOwnProperty(j)) {
res[j] = x[j];
}
}
}
return res;
};
const c = extend({}, a, b);
console.log(c);동작 방식 살펴보기
- 첫 번째 인자인 빈 객체
{}를 병합 결과를 담을 대상으로 사용합니다. - 나머지 인자들을 순차적으로 순회하며 각 객체의 고유 속성(
hasOwnProperty로 판별)만 대상 객체에 복사합니다. - 빈 객체에 복사하기 때문에 원본 객체
a와b는 전혀 영향을 받지 않습니다.
실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 출력이 나타납니다.
{ a: 1, af: [Function: af], b: 2, bf: [Function: bf] }더 간단한 현대적인 방법
참고로 최신 JavaScript(ES6 이상)에서는 위와 같은 함수를 직접 작성하지 않고도 훨씬 간결하게 같은 결과를 얻을 수 있습니다.
Object.assign 사용
const c = Object.assign({}, a, b);스프레드(Spread) 연산자 사용
const c = { ...a, ...b };두 방법 모두 첫 번째 위치의 빈 객체(또는 새 리터럴)에 원본 객체들의 속성을 복사하므로, 원본 객체는 변경되지 않습니다. 실무에서는 코드의 가독성과 유지보수성을 위해 Object.assign이나 스프레드 연산자를 사용하는 것이 권장됩니다.