[SEB_FE] JavaScript - 원시자료형, 참조자료형, 복사

seunghyo·2023년 3월 2일
0

SEB_FE

목록 보기
12/38

1. 원시자료형, 참조자료형


자료형에는 크게 2가지 종류가 있다

  • 원시 자료형(number, string, boolean, undefined, null)

원시 자료형을 변수에 할당하면 메모리 공간에 값 자체가 저장된다.
원시 값을 갖는 변수를 다른 변수에 할당하면 원시 값 자체가 복사되어 전달된다.
원시 자료형은 변경 불가능한 값(immutable value)이다. 즉, 한 번 생성된 원시 자료형은 읽기 전용(read only) 값이다. 재할당을 하고 싶을 때는 새로운 메모리 공간을 확보한다.저장되었던 메모리 공간은 가비지콜렉터에 의해 자동으로 삭제된다.

// 원시 자료형(primitive type): number, string, boolean, undefined, null
42, 'string', true, undefined, null

변수 str에 재할당을 해보자

let str = 'code';
str = 'states';

숫자 타입과 마찬 가지로, 변수 str에 다른 문자열을 재할당하면 새로운 공간을 확보하고 그 공간의 이름이 str이 된다. 그 후에 문자열 ‘states’를 저장합니다. 그 이후 어느 시점에서 가비지콜렉터가 작동할 것이다.
문자열은 원시 자료형이지만 배열처럼 인덱스로 문자열의 각 문자에 접근이 가능하다.

1
2
console.log(str[0]) // 's'
console.log(str[2]) // 'a'

배열과는 달리 인덱스에 직접 다른 문자를 할당하여 값을 변경할 수 없다. 문자열은 원시 자료형이기 때문에 값을 변경할 수 없기 때문이다.

  • 참조 자료형 (배열, 객체, 함수)

참조 자료형을 변수에 할당하면 메모리 공간에 주솟값이 저장된다.
참조 값을 갖는 변수를 다른 변수에 할당하면 주솟값이 복사되어 전달된다.
참조 자료형은 변경이 가능한 값(mutable value)이다.

// 참조 자료형(reference type)
[0, 1, 2] // 배열
{name: 'kimcoding', age: 45} // 객체
function sum (x, y) { return x + y } // 함수

참조 자료형은 변형이 가능하도록 설계되어있다.

arr[3] = '3';
arr.push(4);
arr.shift();

console.log(arr); // [1, 2, '3', 4]

2. 깊은 복사, 얕은 복사


  • 원시 자료형 = 값 자체의 복사
    값 자체가 복사된다는 것은 둘 중 하나의 값을 변경해도 다른 하나에는 영향을 미치지 않는다는 것
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
  • 참조 자료형 = 임의의 저장공간에 값을 저장하고 그 저장공간을 참조하는 주소를 메모리에 저장
    값 자체가 아닌 메모리에 저장되어 있는 주소가 복사
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

slice()

slice()로 배열을 복사할 수 있다. 새 배열은 원본 배열과 같은 요소를 갖지만 참조하고 있는 주소는 다르다.

let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false

Object.assign()

Object.assign()으로 객체를 복사할 수 있다.(얕은 복사)

let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = Object.assign({}, obj);

console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false

spread syntax

객체와 배열 둘 다 복사하는 방법. 변수명 앞에 ... 을 붙인다.

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 = {...obj};

console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false

JSON.stringify()와 JSON.parse()

JavaScript 내부적으로는 중첩된 구조 전체를 복사하는 깊은 복사를 구현할 수 없다. 단, 다른 문법을 응용하여 같은 결과물을 만들 수 있다. JSON.stringify()는 참조 자료형을 문자열 형태로 변환하여 반환하고, JSON.parse()는 문자열의 형태를 객체로 변환하여 반환. 먼저 중첩된 참조 자료형을 JSON.stringify()를 사용하여 문자열의 형태로 변환하고, 반환된 값에 다시 JSON.parse()를 사용하면, 깊은 복사와 같은 결과물을 반환한다. 완전한 깊은 복사를 반드시 해야 하는 경우라면, node.js 환경에서 외부 라이브러리인 lodash, 또는 ramda를 설치하면 된다

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

0개의 댓글