Javascript에서 자료형(type)이란 값의 종류이다.
크게 원시 자료형(primitive type)과 참조 자료형(reference type)으로 나눌 수 있다.
number, string, boolean, undefined, null, symbol
6개의 자료형이 원시 자료형이다.
- 원시 자료형을 변수에 할당하면 메모리 공간에 값 자체가 저장이 된다.
- 원시자료형을 갖는 변수를 다른 변수에 할당하면 원시 값 자체가 복사된다.
- 원시 자료형은 변경불가능한 값이다. 한번 생성된 원시자료형은 읽기 전용 값이 된다.
따라서 string 값의 인덱스를 직접 변경할 수 없다.
원시값은 변경할 수 없다는데 변경이 되네?
변수에 할당된 원시값을 변경하게 되면 메모리 내부에서는 변경된 값을 저장하기 위한 새로운 공간을 확보한 뒤, 그 공간에 변경된 값을 저장하고, 남아있는 기존 값은 사용하지 않으므로 자동으로 메모리에서 삭제합니다. 이런 기능을 가비지 콜렉터(garbage collector)라고 합니다. 그러나 가비지 콜렉터가 어느 시점에 진행되는지는 예측할 수 없습니다.
객체, 배열
- 참조 자료형을 변수에 할당하면 저장공간(heap)에 주솟값이 저장된다.
- 참조 값을 갖는 변수를 다른 변수에 할당하면 주솟값이 복사되어 전달된다.
- 참조 자료형은 변경이 가능한 값(mutable value)이다.
- 복사된 변수의 값을 변경하면 기존 변수의 값도 같이 변경이 된다.
배열 복사
- slice() :
arr.slice()
로 배열을 복사할 수 있다.- spread syntax :
let copiedArr = [...arr]
로 배열을 복사할 수 있다.객체 복사
- Object.assign() :
let copiedObj = Object.assign({}, obj);
으로 객체를 복사할 수 있다.- spread syntax :
let copiedObj = {...obj};
로 객체을 복사할 수 있다.얕은 복사의 한계
- 참조 자료형 내부에 참조 자료형이 중첩되어 있는 경우,
slice(), Object.assign(), spread syntax
를 사용해도 참조 자료형 내부에 참조 자료형이 중첩된 구조는 복사할 수 없다. 참조 자료형이 몇 단계로 중첩되어 있던지, 위에서 설명한 방법으로는 한 단계까지만 복사할 수 있다.
참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사하는 것은 깊은 복사(deep copy)라고 한다. 그러나 JavaScript 내부적으로는 깊은 복사를 수행할 수 있는 방법이 없다. 단, JavaScript의 다른 문법을 응용하면 깊은 복사와 같은 결과물을 만들어 낼 수 있습니다.
1. JSON.stringify()와 JSON.parse()
- 중첩된 참조 자료형을
JSON.stringify()
를 사용하여 문자열의 형태로 변환하고, 반환된 값에 다시JSON.parse()
를 사용하면, 깊은 복사와 같은 결과물을 반환한다.- 한계 : 중첩된 참조 자료형 중에 함수가 포함되어 있을 경우 위 방법을 사용하면 함수가 null로 바뀌게 된다.
- 코드 :
const copiedArr = JSON.parse(JSON.stringify(arr));
2. 외부라이브러리 사용
- 완전한 깊은 복사가 필요하다면 node.js 환경에서 외부 라이브러리인
lodash
, 또는ramda
를 설치하면 된다.const lodash = require('lodash'); const arr = [1, 2, [3, 4]]; const copiedArr = lodash.cloneDeep(arr);
- 참조값을 가지는 변수를 복사한 후 복사한 변수에 원시값을 재할당하면 복사만 변수의 값만 변한다.
let x = { foo: 3 }; let y = x; y = 2; //결과 x = { foo: 3 } , y = 2