학습 목표
- 원시 자료형(primitive data type)과 참조 자료형(reference data type)의 구분이 왜 필요한지 이해할 수 있다.
- 원시 자료형과 참조 자료형의 차이를 이해하고, 각자 맞는 상황에서 사용할 수 있다.
- 원시 자료형이 할당될 때는 변수에 값(value) 자체가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담긴다는 개념을 코드로 설명할 수 있다.
- 참조 자료형은 기존에 고정된 크기의 보관함이 아니라, 동적으로 크기가 변하는 특별한 보관함을 사용한다는 것을 이해할 수 있다.
- 참조 자료형인 값을 복사하는 방법에 대해서 이해한다.
let num = 20;
변수 num을 선언하면 컴퓨터는 num이라는 이름의 공간을 확보
20이라는 원시 값을 그 공간에 저장

num이라는 이름의 저장 공간에 원시 값 20이처럼 원시 자료형은 값 자체를 저장
arr이라는 변수에 0부터 3까지의 숫자를 요소로 가지고 있는 배열을 할당했을 때 일어나는 일(참조 자료형)
let arr = [0, 1, 2, 3];

num과 변수 copiedNum은 동일하게 20이라는 값을 가짐let num = 20;
let copiedNum = num;

let arr = [0, 1, 2, 3];
let copiedArr = arr;

! 만일 원본을 변경한다면? !
원시 자료형
참조 자료형
<원시 자료형>
let num = 20;
num = 30;
변수에 할당된 값이 20에서 30으로 변경되기 때문에 원시 자료형인 숫자 타입의 값이 변경된 것처럼 보임
원시 자료형이 변경 불가능한 값이라는 것

변수에 다른 값을 재할당해도 원시 값 자체가 변경된 것이 아니라 새로운 원시 값을 생성하고, 변수가 다른 메모리 공간을 참조
원시 자료형은 어떤 상황에서도 불변하는 읽기 전용 데이터!!! (원시 자료형이 높은 신뢰성을 가질 수 있는 요인)
남아 있는 값 20
<참조 자료형>
참조 자료형은 변경 가능한 값!!!
크기가 일정하지 않은 참조 자료형의 경우 매번 값을 복사한다면 그만큼 효율성은 떨어짐
arr[3] = '3';
arr.push(4);
arr.shift();
console.log(arr); // [1, 2, '3', 4]

console.log(str[0]) // 's'
console.log(str[2]) // 'a'
slice(), ES6 spread 문법let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
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]
let arr = [0, 1, 2, 3];
console.log(...arr); // 0 1 2 3
let num = [1, 2, 3];
let int = [1, 2, 3];
console.log(num === int) // false
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]
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = Object.assign({}, obj);
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false

let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = {...obj};
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false
slice(), Object.assign(), spread syntax를 사용해도 참조 자료형 내부에 참조 자료형이 중첩된 구조는 복사할 수 없음!!!
let users = [
{
name: "kimcoding",
age: 26,
job: "student"
},
{
name: "parkhacker",
age: 29,
job: "web designer"
},
];
let copiedUsers = users.slice();
console.log(users === copiedUsers); // false

console.log(users[0] === copiedUsers[0]); // true

참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사하는 것을 깊은 복사(deep copy)라고 함
JavaScript 내부적으로는 깊은 복사를 수행할 수 있는 방법이 없음!
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
const arr = [1, 2, [3, function(){ console.log('hello world')}]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, function(){ console.log('hello world')}]]
console.log(copiedArr); // [1, 2, [3, null]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
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