[ONEBITE-REACT] JS 심화 - 원시 타입과 객체 타입 (Primitive Types and Object Types)
정의
- 원시타입 (Primitve Types)
- 단순한 값
- 구성 : 숫자(Number), 문자열(String), 불리언(Boolean), Null, Undefined, Symbol
- 객체 타입 (Object types)
- 여러 속성을 포함할 수 있는 복잡한 데이터 타입
- 구성 : 배열(Array []), 객체(Object {}), 함수(Function), 날짜(Date)
차이
값의 저장 방식에서의 차이
원시 타입
- 변수가 스택 메모리에 직접 저장된다
객체 타입
- 변수가 스택 메모리에 직접 저장되는 것이 아니라 힙(heap) 메모리에 저장된다.
- 변수에는 값이 직접 저장되는 것이 아니라 변수에 대한 참조(reference)가 저장된다.
- 예를 들어 let num = 1 이라는 number 타입의 원시 타입 데이터는 num이라는 변수에 1이라는 값이 직접적으로 저장되는 것이지만, let nums = [1, 2, 3]과 같은 배열, 즉 객체 타입에서는 nums라는 변수에 [1, 2, 3]을 직접 저장하는 것이 아니라 [1, 2, 3]은 heap 메모리에 저장해두고 nums는 저 값이 저장된 메모리의 주소(참조)만 지목하게 되는 것이다.
- let num1 = 1, let num2 = 1 처럼 변수를 여러개 만들어서 같은 값을 저장하게 되면 원시 타입은 메모리에 두 개의 값을 저장하는 것이지만, nums1, nums2와 같이 같은 값의 배열을 여러개 만든다면 이 변수들은 [1, 2, 3]이 저장된 heap 메모리의 주소만 불러오는 것이다.
불변성(Immutability)
원시 타입
- 원시 타입의 값은 변하지 않는다. 한 번 생성된 값은 변경될 수 없고, 값을 변경하려면 새로운 값을 다시 할당해야 한다.
- 변수의 값을 바꿀 수 없기 때문에 변수가 불변(Immutability)하다고 이야기하는 것이 아니라, 한 번 변수가 선언되면 코드 자체를 삭제하지 않는 한 메모리에 계속 저장되어 있기 때문에 불편하다고 하는 것이다.
- let num = 1; num = 10 // 이것은 num의 값을 수정하는 것이 아니라 num이라는 변수에 새로운 값을 할당하는 것이다. // 즉 num이 2라는 새로운 값을 가지게 되었다고 해서 num이 원래 저장했던 1이라는 값이 메모리에서 삭제되는 것은 아니다. 값은 그대로 남아있고 2라는 값이 저장된 메모리를 num이 새로 가리키게 되는 것이다.
객체 타입
- 객체 타입의 값은 가변(mutable)한다. 객체의 속성을 얼마든지 변경하거나 수정하고 삭제할 수 있다.그런데 오히려 이 점 때문에 의도치 않은 문제(Side Effect)를 발생시킬 수 있다. 예를 들어 obj1의 참조를 복사해서 obj2라는 객체를 선언하고 obj2의 값만 추가하고 싶었는데 obj2에 값을 추가하는 순간 obj1의 값도 같이 수정되기 때문이다.
- let obj1 = { name: "장원영" }; let obj2 = obj1;
- let wonYoung = {name: "장원영"}; wonYoung.name = "조유리"; // 위의 예시는 객체의 값을 수정. // 추가 : wonYoung.age = 21; 또는 wonYoung["age"] = 21; // key를 수정 : wonYoung.name = wonYoung.koreanName; // 삭제 : delete wonYoung.name; 또는 delete wonYoung["name"];
obj2\["age"\] = 21;
console.log(obj2); // {name: '장원영', age: 21}
console.log(obj1); // {name: '장원영', age: 21}
위와 같이 obj2의 값만 수정하고 싶었는데 둘 다 age: 21이라는 값이 추가되었다.
이런 경우 obj2를 obj1의 값과 같게 하고 싶다면 obj2 = obj1이 아니라 spread 연산자를 통해서 obj1의 값을 obj2의 값에 퍼뜨려서 초기화 시켜주면 둘이 다른 메모리에 값을 각각 저장하게 되고 가리키는 참조가 달라지게 되기 때문에 obj2는 obj1과 눈에 보이는 값은 같더라도 다른 참조를 가리키기에 서로 영향을 받지 않는다.
let obj1 = { name: "장원영" };
let obj2 = { ...obj1 };
console.log(obj1 === obj2); // false
obj2["age"] = 21;
console.log(obj2); // {name: '장원영', age: 21}
console.log(obj1); // {name: '장원영'}
obj1 = obj2와 같이 객체의 참조값을 복사하는 행위를 얕은 복사(Shallow Copy)라고 하며, 원본 객체가 수정될 수 있어 위험하고
obj2 = {...obj1}과 같이 새로운 객체를 생성하면서 프로퍼티만 따로 복사하는 행위를 깊은 복사(Deep Copy)라고 하며 원본 객체가 수정될 일이 없어 안전하다.
깊은 복사를 하는 방법은 spread 연산자 뿐만 아니라 재귀적 복사 함수, JSON.stringify() 메서드를 이용한 방법, lodash와 같은 라이브러리를 이용하는 방법 등으로 다양하다.
변수 할당
원시 타입
- 원시 타입에서는 값이 변수에 직접 저장된다. 따라서 변수를 할당한다는 것은 값을 복사하는 것을 의미한다.
- let num1 = 1; let num2 = num2; // 이것은 num1의 값을 num2에 복사한 것이다. 즉 두 개의 변수를 선언했기 때문에 메모리셀 두 개를 차지하는 정보이다.
객체 타입
- 객체 타입에서는 값이 변수에 직접 저작되는 것이 아니라 변수의 값의 참조(메모리셀의 주소 또는 위치)가 저장되는 것이다. 따라서 변수 간 할당하는 것은 참조만 복사되는 것이기에 두 변수가 결국 같은 객체를 가리키게 되는 것이다.
- let obj1 = {name : "장원영"}; let obj2 = obj1 // 이것은 obj2에 obj1의 값인 {name: "장원영"}을 복사해서 변수가 메모리 셀 두개를 차지하는 것이 아니라 "장원영"이라는 메모리셀이 저장된 참조(주소)만 obj2가 obj1과 동일하게 지목하는 것이다.
동일성 비교
원시 타입
- 값의 동일성을 비교할 때 값 자체를 비교한다.
- let num1 = 1; let num2 = 1; console.log(num1 === num2); // true // num1과 num2의 값이 1로 동일하기 때문에 true가 출력된다.
객체 타입
- 값의 동일성을 비교하는 것이 아니라 참조의 동일성을 비교하게 되는데, 객체가 저장된 메모리셀의 주소를 비교한다.
- let obj1 = {name: "장원영"}; let obj2 = {name: "장원영"}; console.log(obj1 === obj2); // false // 객체 타입에서의 비교는 "장원영"이라는 값을 비교하는 것이 아니라, obj1이 가리키고 있는 메모리셀의 참조(주소)와 obj2가 가리키고 있는 메모리셀의 참조를 비교하게 된다. // 그런데 이 경우 name: "장원영"이라는 값을 두 번 만들었기에 서로 다른 메모리셀에 저장되어 있기 때문에 obj1과 obj2가 가리키는 메모리셀의 주소가 다르다. 따라서 false가 출력된다.
얕은 비교와 깊은 비교
만약 위와 같이 객체의 참조값이 같은지 비교하는 얕은 비교가 목적이 아니라 객체의 프로퍼티가 같은지 비교하려는 깊은 비교가 목적이라면 위와 같이 얕은 비교를 하는 것이 아니라 JSON.stringify()라는 자바스크립트 내장 함수를 사용하여 깊은 비교를 해야 한다.
let obj1 = { name: "장원영" };
let obj2 = { ...obj1 };
console.log(obj1 === obj2); // false
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // true
'Programing > React' 카테고리의 다른 글
[ONEBITE-REACT] 020. JS 심화 - 배열 메서드 1. 요소 조작 (0) | 2024.03.20 |
---|---|
[ONEBITE-REACT] JS 심화 - 반복문으로 배열과 객체 순회하기 (Iteration) (0) | 2024.03.15 |
[ONEBITE-REACT] JS 심화 - Spread 연산자 & Rest 매개변수 (1) | 2024.03.14 |
[ONEBITE-REACT] JS 심화 - 구조 분해 할당(Destructing Assignment) (0) | 2024.03.14 |
[ONEBITE-REACT] JS 심화 - 단락 평가 (Short-circuit Evaluation) (0) | 2024.03.12 |
댓글