원시값과 참조값
원시값은 변경할 수 없다. (변수를 변경할 수 없다는 것이 아니다.)
그렇기 때문에 원시값을 할당한 변수를 재할당하면 새로운 메모리 공간에 새로운 값을 재할당한다.
하지만 참조값은 메모리 공간의 주소를 가리킨다. 이 주소를 참조값이라고 하는데 이 참조값에 접근하여 객체에 접근하는 방식이다.
같은 참조를 공유하는 객체들은 1개 이상일 수 있고, 같은 참조를 공유하는 객체들은 서로 사이드이팩트를 일으킬 수 있따.
얕은 복사
복사를 새로운 메모리 공간을 만드는 것이라고 정의했을때,
얕은 복사는 1depth까지만 복사를 한다는 뜻이다.
즉, 2depth부터는 같은 참조를 가리키기 때문에 사이드이펙트가 일어난다.
전개구문을 이용하여 얕은복사를 할 수 있다.
const a = {name:'j',a:{b:2}}
const b = {...a}
b.name='kk'
// 얕은 복사는 1depth까지 새로운 메모리에 할당한다.
// b.name의 변화가 a.name에 영향을 미치지 않음
console.log(a) // {name:'j', a:{b:55}}
b.a.b=666
// 2depth부터는 참조를 공유하기 떄문에 변화도 공유한다.
// b.a.b의 변화가 a.a.b에 영향을 준다.
console.log(a) // {name:'j', a:{b:666}}
깊은 복사
아예 새로운 메모리 공간에 객체를 새롭게 할당한다.
이는 서로 참조를 공유하지 않는 복사이기 때문에 사이드이펙트가 나타나지 않는다.
깊은복사 하는 방법은 structuredClone()을 이용하면 된다.
최근에 JS 스펙으로 나온 방식이다.
structuredClone이 나오기 전까지는 아래 방법으로 깊은복사를 했다.
1. 재귀적으로 깊은 복사 수행
가장 귀찮은 방법이다. 사용하는 Object의 Depth가 길어질수록 Time Complexity(시간복잡도)도 늘어난다.
2. Lodash의 cloneDeep 함수 사용
자바스크립트 고차함수 집합 및 함수형 라이브러리다.
완벽히 깊은 복사를 할 수 있다.
3. JSON.parse()와 JSON.stringify() 함수 사용
JSON.stringify() 를 사용해서 Object 전체를 문자열로 변환한다. 이때 문자열로 변환되면서 참조 값이 끊긴다.
다시 JSON.parse()를 사용해서 문자열을 Object 함수로 변환한다. 이때의 변환된 Object는 참조를 공유하지 않는, 즉 완전히 독립적인 메모리를 차지하는 Object 이다.
하지만 JSON함수는 엄청나게 리소스를 잡아먹는 함수인 만큼 성능이 좋지 않음을 고려해야 한다.
'개발 > Javascript' 카테고리의 다른 글
JS : 배열과 유사배열 (0) | 2021.08.09 |
---|---|
js : break, continue (0) | 2021.08.07 |
js 클로저 (0) | 2021.08.04 |
JS : 선언자 let, const가 var보다 권장되는 이유 (0) | 2021.08.04 |
JS : 변수의 유효범위 Scope, 지역변수와 전역변수 (0) | 2021.08.04 |