원시 타입 ( Primitive Type )
원시 타입에 속하는 데이터 타입에는 아래와 같이 6가지가 존재한다.
- Number & Bigint
- String
- Boolean
- null
- unjdefined
- Symbol
객체 타입은 원시 타입을 제외한 나머지 객체 타입(참조)이라 할 수 있다.
객체의 하위 분류에 속하는 데이터 타입은 아래와 같다.
- Array
- FUnction
- Date
- RegExp 등등
원시 타입과 객체 타입은 크게 세 가지 측면에서 다르다.
쉽게말해 원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 pass by value 이라 한다.
객체를 가리키는 변수를 다른 변수에 할당하면 우너본의 참조 값이 복사되어 전달된다. 이를 pass by reference 이라 한다.
원시 값
immutability
- 원시 타입의 값, 즉 원시 값은 변경 불가능한 값이다. (immutable value)
- 쉽게 말해 한번 생선된 원시 값은 읽기 전용 값으로서 변경할 수 없다. 이러한 원시 값의 특성은 데이터의 신뢰성을 보장한다.
- 그 전에 변수와 값을 명확히 구분해야한다.
- 변수 : 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름
- 값 : 변수에 저장된 데이터로서 표현식이 평가되어 생성된 결과를 말한다.
- 상수 : 재할당이 금지된 변수
- 변경 불가능하다는 것은 변수가 아니라 값에 대한 진술이다.
- 원시값을 할당한 변수에 새로운 원시 값을 재할당하면 메모리 공간에 저장되어 있는 재할당 이전의 원시 값을 변경하는 것이 아니라
새로운 메모리 공간을 확보하고 재할당한 원시 값을 저장한 후 변수는 새롭게 재할당한 원시 값을 가리킨다.
이때 변수가 참조하던 메모리 공간의 주소가 바뀐다. 값의 이러한 특성을 불변성 이라고 한다. (아래 그림) - 불편성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 수 있는 방법이 없다.
str에 "문자열"이라는 값을 할당한 후 "문자열2"라는 값을 재할당하면 새로운 메모리에 재할당한 값인 "문자열2"가 저장되고 변수가 그 메모리를 가리키게 되는 것을 알 수 있다.
원시 타입의 값 복사하기
var score = 80;
var copy = score;
console.log(score); // 80
console.log(copy); // 80
score = 100;
console.log(score); // 100
console.log(copy); // ???
저 물음표에 무엇이 출력될지 예상해보자
copy는 score로 부터 80이라는 값을 전달 받고 이것을 우리는 "값에 의한 전달" 이라고한다.
이때 전달받은 80이라는 값은 동일하지만 그 값이 저장되는 메모리 저장 장소는 다르다.
따라서 score = 100 으로 다시 재할당이 되어도 copy는 메모리 저장 장소가 다르기 때문에 영향이 없다 고로 ???는 여전히 80이다.
원시 타입의 값은 한 번 만들면 절대 바꿀 수 없다. 이러한 원시 값의 특성은 데이터의 신뢰성을 보장한다.
자 그럼 여기서 메모리 저장 장소를 똑같게 하려면 어떻게 해야할까?
var score, copy = 80;
이렇게 하면된다. 여기서 score = 100을 하면 score만 바뀐다.
문자열과 불변성
문자열은 원시값이다.문자열은 유사 배열 객체이면서 이터러블이므로 배열과 유사하게 각 문자에 접근할 수 있다.하지만 일부 문자를 변경해도 반영되지않는다 왜? 문자열은 변경 불가능한 값이기 때문이다.
객체 타입 (Object / Reference Type)
객체 타입과 원시 타입의 가장 큰 차이점은 객체의 변수(프로퍼티) 영역이 추가로 존재한다는 것이다.
예를 들어,
var obj1 = {
a: 1,
b: "bbb"
}
이렇게 생긴 객체를 선언 및 초기화할 때 생기는 일에 대해 알아보자.
1. 먼저 변수 영역의 빈 공간(@1002)을 확보하고 주소의 이름을 obj1로 지정한다.
2. 임의의 데이터 저장 공간(@5001)에 데이터를 저장하려니 여러 프로퍼티로 이루어진 데이터 그룹이므로,
그룹 내부 프로퍼티들을 저장하기 위한 별도의 변수 영역을 마련하고 그 영역의 주소(@7103~)를 @ 5001에 저장한다.
3. @7103과 @7104에 각각 a,b라는 프로퍼티 이름을 지정한다.
4. 데이터 영역에서 1을 검색하고, 없으므로 임의로 @5003에ㅔ 저장한 뒤 이 주소를 a가 가리키도록 @7103에 저장한다.
"bbb"도 이와 같은 과정을 거친다.
위로부터 알 수 있듯 데이터 영역에 저장된 값들은 모두 불변값이지만, 객체가 별도로 할애한 영역은 "변수 영역"이고 여기에는 얼마든지 다른 값을 대입할 수 있다.
이 때문에 참조형 데이터는 불변하지 않는 값, 즉 가변값이라고 한다.
객체 타입의 값 복사하기
mutable
- 메모리를 효율적으로 사용하기위해 그리고 객체를 복사해 생성하는 비용을 절약하여 성능을 향상시키기 위해 객체는 변경 가능한 값으로 설계되어있다.
객체 타입의 변수들은 데이터 복사가 일어날 때 값이 담긴 주솟값을 바로 복사하지 않고, 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복사한다.
참조에 의한 전달
- 얕은 복사라고도 한다.
var person = {
name: "Lee"
};
// 참조 값을 복사(얕은 복사)
var copy = person;
copy.name = "KIM";
person.address = "Soul";
// copy와 person은 동일한 객체를 가리킨다.
// 따라서 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받는다.
console.log(person); // {name: "Kim", address: "Seoul"}
console.log(copy); // {name: "Kim", address: "Seoul"}
위 코드에서, copy는 person이 가리키는 데이터 묶음의 주소를 복사한다.
그러므로 copy에서 프로퍼티의 값을 변경하면, 같은 객체의 주소를 가지고 있는 person에서도 값이 변하게 되는것이다.
하지만,
var obj1 = {
a: 1,
b: "bbb"
};
var obj2 = obj1;
obj2 = {
a: 20,
b: "cc"
};
console.log(obj1.a); // 1
이처럼 복사 후 obj2에 새로운 객체를 할당해 주게 되면 메모리 데이터 영역의 새 공간에 새로운 객체가 저장되고
그 주소를 변수 영역의 obj2에 저장하게 된다.
즉 obj1과 obj2가 다른 객체를 가리키게 되므로 obj1이 가리키는 값은 달라지지 않는다.
이로부터 알 수 있는 점은, 참조형 데이터를 가변값이라 할 때의 "가변"은 참조형 데이터 자체를 변경할 때(두 번째 경우)가 아니라 그 내부의 프로퍼티를 변경할 때(첫 번째 경우)에만 성립한다는 것이다.
새로운 단어 정리 🔖
유사 배열 객체(array-like object)
: 배열과 같이 인덱스([])로 프로퍼티 값에 접근할 수 있고,
length 프로퍼티를 갖는 객체를 말한다.
+ 문자열이 이에 해당한다.
단, 이미 생성된 문자열의 일부 문자를 변경해도 반영되지 않는다.
얕은 복사와 깊은 복사(shallow copy and deep copy)
: 원본과는 참조 값이 다른 별개의 객체이다.
얕은 복사 = 객체 안에 중첩되어 있는 객체는 참조 값을 복사,
즉 사본을 만들어내지 않고 원본을 참조하도록 복사한 척 하는 것<원본과의 연결은 끊어진다>
깊은 복사 = 객체 안에 중첩되어 있는 객체까지 모두 복사 (원시 값처럼 완전한 복사본)
완벽하게 원복과 사본을 나눠 복사하는 방법
sorce : 자바스크립트 deep dive
'Javascript > 개념' 카테고리의 다른 글
[JS] 배열을 복사하는 여러가지 방법 (1) | 2023.11.12 |
---|---|
[JS - 개념] 재귀함수와 증감연산자를 사용할 때 주의점 (1) | 2023.10.15 |
[JS - 놓치기 쉬운 개념] parseInt() 개념 및 주의할 점들 (0) | 2023.09.05 |
[JS - 개념] Sort() <배열 고차함수> (0) | 2023.05.26 |
[JS - 개념] String.prototype.replace() (0) | 2023.01.31 |