학습 목표
- 원시 자료형(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