[JS] 원시타입과 참조타입, 그리고 얕은 복사(spread operator?)

Bomin·2023년 3월 27일
1

[JavaScript]

목록 보기
3/6
post-thumbnail

💡 원시타입과 참조타입

🔆 원시 타입

  • 원시값(primitive): 변경 불가능한 불변의 값
  • String, Number, undefined, Boolean, Symbol, BigInt 6종류

💦 원시 타입의 불변성(immutable)

  • 변수의 변경 ≠ 원시값의 변경
  • 변수: 값을 담고 있는 메모리 공간 자체, 메모리 공간 주소를 가르키는 식별자
let a; //주소: 0x01234 값: Undefined
a = 10; //주소: 0x02345 값: 10
  • 원시 값 undefined, 10(number) 는 변경 불가능하므로 원시값을 재할당한다.
  • 재할당: 새 메모리 공간 확보 후 값 저장한 후 변수가 참조하던 주소값을 변경해서 이루어진다.
  • 따라서 원시값은 불변성을 유지하고 변수가 가리키는 메모리 주소를 바꿔가며 변수 값을 변경한다.

💦 상수와의 차이

  • 상수는 단순히 변수의 재할당이 금지된 것!
  • 원시값이 불변성을 가지는 것과 의미가 다르다.

💡 원시 타입의 복사(by value)

  • 원시값은 값 그대로(by value) 저장, 할당, 복사
  • 값을 복사할 뿐 별개의 메모리 공간을 가진다!
  • 각 변수에 무슨 짓을 하든 서로에게 영향을 주지 않는다.
// 원시타입은 값이 복사되어 전달
let a = 1;
let b = a; //1
b = 2;
console.log(a); //1
console.log(b); //2

🔆 참조 타입

  • 원시 타입을 제외한 나머지는 참조 타입 → 객체 Object
  • 객체 값을 갖는 변수: 객체의 메모리 주소를 참조한다
  • Object의 데이터 자체는 별도의 메모리 공간(heap)에 저장
  • 변수에 할당 시 데이터에 대한 주소(힙(Heap) 메모리의 주소값)가 저장
  • 자바스크립트 엔진이 변수가 가지고 있는 메모리 주소를 이용해서 변수의 값에 접근!

💡 객체의 복사(by reference)

  • 객체는 참조에 의해(by reference) 저장, 복사
  • 변수 obj 엔 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어있는 '메모리 주소’인 객체에 대한 '참조 값’이 저장
// 객체타입은 참조값(메모리주소, 레퍼런스)가 복사되어 전달
let obj = {
	//0x1234
  name: 'apple',
};
let obj2 = obj;  //참조값을 복사 - 0x1234

console.log(obj); //{ name: 'apple' }
console.log(obj2); //{ name: 'apple' }

obj2.name = 'banana';

console.log(obj); //{ name: 'banana' }
console.log(obj2); //{ name: 'banana' }
  • 객체의 값을 복사한 후 프로퍼티의 내용을 변경하고자 할 때 → 단순히 객체를 복사한 다음 프로퍼티를 수정하면 원본 객체의 프로퍼티까지 변경됨‼️
  • 복사한 객체 obj2는 새로운 값을 할당한 게 아니라 obj 객체의 주소값을 단순히 참조하고 있기 때문
//참조하고 있는 주소값이 같다.
console.log(obj == obj2); //true
console.log(obj === obj2); //true

이렇게 원래 값과 복사한 값이 같은 주소값을 보고 있으면 얕은 복사

🔆 얕은 복사와 깊은 복사

🌼 Spread Operator

  • 완전히 원본 주소와 참조를 끊어주는 방법을 사용해야 내부 프로퍼티 값을 변경하더라도 복사한 원본 객체의 값이 바뀌지 않는다.
  • 이 때 원본의 값을 변경시키지 않고, 복사한 객체의 프로퍼티 값만 변경하는 방법 Spread Operator (...) 가 있다.
let obj = {
  name: 'apple',
};
let obj2 = { ...obj, name: 'orange' };

console.log(obj); //{ name: 'apple' }
console.log(obj2); //{ name: 'orange' }

console.log(obj === obj2); //false
  • 이제 obj2는 단순히 obj의 주소값을 참조만 하는게 아니라 새로운 주소값에 값을 할당하므로 false

💦 그렇다면 Spread Operator는 얕은 복사? 깊은 복사?

let a = [[1], [2], [3]];
let b = [...a];
b.shift().shift(); // 1

console.log(b); //[ [ 2 ], [ 3 ] ]
console.log(a); //[ [], [ 2 ], [ 3 ] ]

참고:  Spread 문법은 배열을 복사할 때 1 레벨 깊이에서 효과적으로 동작합니다. 그러므로, 위와 같이 다차원 배열을 복사하는것에는 적합하지 않을 수 있습니다. (Object.assign()과 전개 구문이 동일합니다)

💡 Spread Operator로 복사한 객체(배열)은 1depth의 값에서만 깊은 복사를 실행한다!

완전한 깊은 복사를 구현하려면? - 이 방법에 대해서 공부해서 새 글로 정리할 예정.

참고자료
🌱☀️

profile
Frontend-developer

0개의 댓글