객체 복사하기(얕은·깊은) | ddalpange
[출처 : ddalpange.log]
시작하기 전에
# 예제 A
const a = 1;
const b = a;
b = 2;
console.log(a, b);
# 예제 B
const a = { p : 1 };
const b = a;
b.p = 2;
console.log(a.p, b.p);
자바스크립트는 불변형의 데이터를 선언할 때 포인터와 값 모두 생성하지만,
오브젝트(배열)을 생성할 때에는 메모리 절약을 위해 포인터만 새로 할당할 뿐이다. 위 예제의 해석은
- 예제 A는 b에 a를 복사하였다.
- 예제 B는 b에 a를 대입하였다.
단순히 대입연산자(=)를 통해 변수를 대입하는것과 얕은 복사는 엄연히 다르다.
예제 B에서 b에 a를 복사하는 방법에는 다음과 같다.
1. Object.assign()을 이용
var object1 = {"name":AGAL, age:20};
function cloneObject(obj) {
return Object.assign({}, obj);
}
var obeject2 = cloneObject(object1);
# Object.assign()
첫번째 인자로 들어오는 객체에 두번째 인자로 들어오는 객체의 프로퍼티들을 차례대로 덮어쓰기하여 반환하는 메소드이다.
*여기서 주의할 점은 Object.assign()은 프로퍼티들에 대한 참조를 덮어쓰기하기 때문에,
오브젝트 안에 오브젝트 또는 배열이 있을 경우 복사가 아닌 참조를 하게된다. 즉 객체를 얕은 복사(Shallow Copy)한다
2. JSON 객체의 메소드를 이용
function cloneObject(obj) {
return JSON.parse(JSON.stringify(obj));
}
# JSON.stringify()
자바스크립트 오브젝트를 스트링 포멧으로 변환하는 메소드이다.
# JSON.parse()
스트링 포멧을 자바스크립트 오브젝트로 변환하는 메소드이다.
*스트링으로 변환하였다가 다시 오브젝트로 변환하기 때문에 이전 객체에 대한 참조가 없어지지만 JSON 메소드 자체가 성능면에서 다른 방법에 비해 굉장히 느리기 때문에 주의해야한다. 이 방법은 객체를 깊은 복사(Deep Copy)한다.
3. 자바스크립트 재귀 사용
function cloneObject(obj) {
var clone = {};
for(var i in obj) {
if(typeof(obj[i])=="object" && obj[i] != null)
clone[i] = cloneObject(obj[i]);
else
clone[i] = obj[i];
}
return clone;
}
오브젝트의 프로퍼티들을 순회하여 빈 오브젝트에 더한다.
그 과정에서 원본 오브젝트의 프로퍼티가 오브젝트일 경우 재귀적으로 함수를 실행한다. 이 방법은 객체를 깊은 복사(Deep Copy)한다.
4. Immutable.js 사용
import { Map } from 'immutable';
const map = Map({a : 1});
const newMap = map;
newMap.set('a', 2);
console.log(map.get('a'));
console.log(newMap.get('a'));
페이스북에서 만든 오픈소스 라이브러리이다. Immutable.js를 쓰게된다면 Array, Map 모두 이뮤터블하게 쓸 수 있게된다.
*객체의 내부 값을 변경해도 원본 객체의 값은 변화하지 않고 새로운 객체를 배출한다는 뜻이다.
5. Spread 문법 사용 (ES6)
function cloneObj(obj) {
return { ...obj }
}
Spread 구문을 사용하면 배열이나 문자열과 같이 반복 가능한 문자를 0개 이상의 인수 (함수로 호출할 경우) 또는 요소 (배열 리터럴의 경우)로 확장하여, 0개 이상의 키-값의 쌍으로 객체로 확장시킬 수 있다. 즉 객체를 얕은 복사(Shallow Copy)한다.