< 원시 자료형과 참조 자료형>
자료형이란?
JavaScript에서 자료형(type)이란 값(value)의 종류.
자료형은 크게 두 가지로 구분할 수 있는데, 원시 자료형(primitive type)과 참조 자료형(reference type)이다.
원시 자료형
6개의 자료형 number, string, boolean, undefined, null, symbol (이중 symbol 타입은 잘 사용되지 않는 타입)
원시자료형의 특징
- 원시 자료형을 변수에 할당하면 메모리 공간에 값 자체가 저장된다.
- 원시 값을 갖는 변수를 다른 변수에 할당하면 원시 값 자체가 복사되어 전달된다.
- 원시 자료형은 변경 불가능한 값, 한 번 생성된 원시 자료형은 읽기 전용 값이다.
값 자체를 저장
변수(num)를 선언하면 컴퓨터는 num이라는 이름의 공간을 확보하고 20이라는 원시 값을 그 공간에 저장.
let num = 20; // 이처럼 원시 자료형은 값 자체를 저장
원시 자료형을 할당한 변수를 다른 변수에 할당하면 값 자체의 복사가 일어난다.
let num = 5;
let copiedNum = num;console.log(num); // 5
console.log(copiedNum); // 5
console.log(num === copiedNum); // true
값 자체가 복사된다는 것은 둘 중 하나의 값을 변경해도 다른 하나에는 영향을 미치지 않는다는 것을 의미한다.
copiedNum = 6;
console.log(num); // 5
console.log(copiedNum); // 6
console.log(num === copiedNum); // false
참조 자료형
원시 자료형이 아닌 모든 자료형. 여러 데이터를 한 번에 다룰 수 있는 배열, 객체가 대표적인 참조 자료형이다. 함수 또한 참조 자료형으로 분류된다.
> [0, 1, 2] // 배열
{name: 'kimcoding', age: 45} // 객체
function sum (x, y) { return x + y } // 함수
참조 자료형의 특징
- 참조 자료형을 변수에 할당하면 메모리 공간에 주솟값이 저장된다.
- 참조 값을 갖는 변수를 다른 변수에 할당하면 주솟값이 복사되어 전달된다.
- 참조 자료형은 변경이 가능한 값이다.
주솟값을 저장
let arr = [0, 1, 2, 3]; // 배열의 요소 각각이 하나의 값이기 때문에 하나의 공간에 배열 자체를 저장하는 것은 불가능
JavaScript는 특별한 저장 공간(heap)에 참조 자료형을 저장한 후, 그 저장공간을 참조할 수 있는 주소값을 변수에 저장.
변수 arr에 해당하는 저장공간에는 주소값이 저장되어 있고, 그 주소값을 통해 참조 자료형에 접근할 수 있다.
이를 참조한다(refer)고 한다.
참조 자료형은 임의의 저장공간에 값을 저장하고 그 저장공간을 참조하는 주소를 메모리에 저장하기 때문에
다른 변수에 할당할 경우 값 자체가 아닌 메모리에 저장되어 있는 주소를 복사.
let arr = [0, 1, 2, 3];
let copiedArr = arr;
console.log(arr); // [0, 1, 2, 3]
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr) // true
따라서 둘 중 하나를 변경하면 해당 변수가 참조하고 있는 주소에 있는 값이 변경되기 때문에 다른 하나에도 영향을 미치게 된다.
copiedArr.push(4);
console.log(arr); // [0, 1, 2, 3, 4]
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr === copiedArr) // true
< 얕은 복사와 깊은 복사 >
얕은 복사란?
참조 자료형 내부에 참조 자료형이 중첩되어 있는 경우, 중첩된 구조는 복사할 수 없다.
중첩된 구조 중 한 단계까지만 복사하는것을 얕은 복사(shallow copy)라고 한다.
slice(), Object.assign(), spread syntax 등의 방법이 있다.
◇ 배열 복사하기
1. slice()
배열 내장 메서드인 slice()를 사용하면 원본 배열 복사 가능.
let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
2. spread syntax
spread syntax는 ES6에서 새롭게 추가된 문법으로, spread라는 단어의 뜻처럼 배열을 펼칠 수 있다.
펼치는 방법은 배열이 할당된 변수명 앞에 ... 을 붙여주면 된다.
let arr = [0, 1, 2, 3];
let copiedArr = [...arr];
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]
◇ 객체 복사하기
1. Object.assign()
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = {...obj};
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false
2. spread syntax
spread syntax는 배열뿐만 아니라 객체를 복사할 때도 사용 가능.
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = {...obj};
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false
깊은 복사란?
참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사하는 것.
하지만 JavaScript 내부적으로는 깊은 복사를 수행할 수 있는 방법이 없기 때문에, JavaScript의 다른 문법을 응용해야 한다.
1. JSON.stringify()와 JSON.parse()
JSON.stringify() 참조 자료형을 문자열 형태로 변환하여 반환
JSON.parse() 문자열의 형태를 객체로 변환하여 반환
먼저 중첩된 참조 자료형을 JSON.stringify()를 사용하여 문자열의 형태로 변환하고,
반환된 값에 다시 JSON.parse()를 사용하면, 깊은 복사와 같은 결과물을 반환할 수 있다.
const arr = [1, 2, [3, 4]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
이 방법 또한 깊은 복사가 되지 않는 예외가 존재한다.
중첩된 참조 자료형 중에 함수가 포함되어 있을 경우 위 방법을 사용하면 함수가 null로 바뀌게 된다.
2. 외부 라이브러리 사용
완전한 깊은 복사를 반드시 해야 하는 경우라면, node.js 환경에서 외부 라이브러리인 lodash 또는 ramda를 설치하면 가능하다.
아래는 lodash의 cloneDeep을 사용한 깊은 복사의 예시이다.
const lodash = require('lodash');
const arr = [1, 2, [3, 4]];
const copiedArr = lodash.cloneDeep(arr);
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
〉〉 총 정리를 해보자면,
- 배열의 경우 slice() 메서드 또는 spread syntax 등의 방법으로 복사할 수 있다.
- 객체의 경우 Object.assign() 또는 spread syntax 등의 방법으로 복사할 수 있다.
- 위 방법으로 참조 자료형을 복사할 경우, 중첩된 구조 중 한 단계까지만 복사된다. (얕은 복사)
- JavaScript 내부적으로는 중첩된 구조 전체를 복사하는 깊은 복사를 구현할 수 없다. 다른 문법을 응용하여 같은 결과물을 만들 수 있다.
- 깊은 복사에는 대표적인 JSON.stringify()와 JSON.parse()를 사용하는 방법이 있지만, 예외의 케이스가 존재한다. (참조 자료형 내부에 함수가 있는 경우)
- 완전한 깊은 복사를 반드시 해야 하는 경우, node.js 환경에서 외부 라이브러리인 lodash, 또는 ramda를 사용하면 된다.
'JavaScript' 카테고리의 다른 글
비동기 처리방식 - Promise /async & await (1) | 2023.04.18 |
---|---|
[객체 지향 프로그래밍]프로토타입 체인 (0) | 2023.03.16 |
[객체 지향 프로그래밍] 프로토타입과 클래스 (0) | 2023.03.15 |
객체 지향 프로그래밍(OOP)이란? (0) | 2023.03.15 |
[객체 지향 프로그래밍]class 와 instance (0) | 2023.03.15 |