2021. 4. 29. 18:34ㆍFront-end/Javascript
변수 - primitive 타입과 object 타입 변수의 차이점
🍋 리액트를 공부할 때 PureComponent와 관련해서 shallow comparison 을 이해하기 위해 먼저 알아두어야 할 개념이다.
1. primitive(원시 타입) 변수
- primitive(원시 타입) 변수 : number, string, boolean, null, undefined, symbol
let number = 2;
이렇게 primitive 타입 변수는 변수를 선언함과 동시에 메모리에 공간이 생기게 되고 그 공간에 데이터가 적재되어진다.
let number = 2;
let number2 = number;
console.log(number); // 2
console.log(number2); // 2
이렇게 number2 = number라고 하면 어떤 일이 발생하는 것일까?
이렇게 number2만을 위한 공간이 따로 생기고, number에서 값을 복사해오는 것이다.
let number = 2;
let number2 = number;
console.log(number); // 2
console.log(number2); // 2
number2 = 3;
console.log(number); // 2
console.log(number2); // 3
그런데 여기 number2에 새로운 값인 3을 할당한다면? number에는 반영이 되지 않고 number2에만 값이 반영된다.
이는 처음에 number에 있는 값을 "복사" 해서 number2에 가져온 것이기 때문에,
후에 number2에서 값을 변경하더라도 number의 값에 전혀 영향을 주지 않는다.
(프린트해서 복사본에 낙서를 하더라도 원본까지 영향을 주지는 않듯이)
2. Object(객체) 타입 변수
- primitive 타입을 제외한 변수는 모두 Object 타입이라고 할 수 있다.
- 여러 개의 데이터를 한 군데에다 묶어놓은 것
- 배열, 리스트, 함수, 객체 등
- Object 타입은 너무 담을 데이터가 많기 때문에 단순히 변수를 선언하는 box에 다 담아둘 수 없다.
let obj = {
name: '홍길동',
age: 20,
}
이렇게 되면 메모리에 무슨 일이 벌어질까?
name과 age도 각각 변수로 생각할 수 있기 때문에 따로 저장이 되고 name과 age를 묶어서 x123이라는 주소에 저장이 된다고 하자. 이 때 obj라는 변수는 x123이라는 주소를 저장하고 있는 것이다.
let obj = {
name: '홍길동',
age: 20,
}
console.log(obj.name); // 홍길동
이렇게 obj.name이라고 하게 되면 obj가 가리키는 곳의 주소로 가서 거기서 name을 찾아오는 것이다.
let obj = {
name: '홍길동',
age: 20,
}
console.log(obj.name); // 홍길동
let obj2 = obj;
이렇게 obj2 = obj하면 무슨 일이 벌어질까?
변수를 할당할 때에는 무조건 그 변수에 들어가 있는 값이 복사 되어 들어온다.
그러므로 이 경우에는 obj안에 들어있는 x 123 주소가 복사되어 obj2에 들어오는 것이다.
let obj = {
name: '홍길동',
age: 20,
}
console.log(obj.name); // 홍길동
let obj2 = obj;
obj.name = '강동원';
console.log(obj.name); // 강동원
console.log(obj2.name); // 강동원
만약 obj.name을 변경한다면?
obj.name과 obj2.name이 둘다 변경이 된 것을 볼 수가 있다.
이것을 그림으로 이해한다면 다음과 같다.
즉 object 타입에는 값이 아니라 참조(reference)가 복사되어지기 때문에 오브젝트를 이용해서 값을 변경하게 되면 복사된 객체에서도 값이 반영이 되는 것이다.
왜 객체 타입은 const를 사용해도 값이 재할당이 되는가?
- primitive 타입에서는 const로 변수를 선언하게 되면 값을 변경하는 것이 불가능하다.
- ❓ 그런데 왜 const를 object 타입에서는 사용하더라도 값을 변경할 수 있는걸까?
const obj = {
name: '홍길동',
age: 20,
};
obj.name = '강동원';
// const이지만 객체 자체가 바뀐 것은 아니기 때문에 그 안에 있는 변수들은 변경을 해도 된다.
const로 객체를 선언했으나 사실 obj가 가르키는 것은 주소이기 때문에 그 안의 값을 변경해도 변경이 가능하다. (그릇은 그대로 이기 때문에)
const obj = {
name: '강동원',
age: 20,
};
/* 이렇게 할당하는 것은 불가능하다.
obj = {
name: '김연아',
age: 25,
};
*/
하지만 객체를 아예 새로 선언하는 것은 그릇이 아예 바뀌는 것이기 때문에 const에서 이렇게 하면 불가능하다.
⭐즉, const로 객체를 선언하면, 레퍼런스 자체는 변경이 불가능하지만 그 안에 담긴 값은 변경이 가능하다.
리액트에서도 알아두어야 할 내용
const array = [
// array의 주소 : x333
{ id: 1, name: "홍길동", age: 20 },
// x111
{ id: 2, name: "김연아", age: 25 },
// x222
];
const array2 = array; // array2의 주소 : x333
const array3 = [...array]; // array3의 주소: x666
(주소는 임의로 설정한 것이다.)
array2의 경우에는 array를 바로 복사해왔기 때문에 array의 주소값인 x333을 가지고 있다.
그러나 array3의 경우에는 비구조화할당 문법을 이용하여 array 안에 들어있는 값들을 그대로 복사해온 것일 뿐 그릇 자체는 새 그릇이기 때문에 아예 새로운 주소값인 x666을 가진다고 생각할 수 있다.
array.name = '강동원';
console.log(array.name); // 강동원
console.log(array2.name); // 강동원
console.log(array3.name); // 강동원
이때 array에서 id가 1인 객체의 name을 강동원으로 변경하게 되면 array2는 물론이고 array3도 값이 변경이 된다. 왜냐하면 array3도 array에 들어있는 값을 그대로 복사해서 가져왔었기 때문에, id가 1인 객체의 주소값인 x111을 가지고 있기 때문에 똑같은 객체를 가리키고 있기 때문이다.
array.push({id: 3, name: '아이린', age: 20});
console.log(array.length); // 3
console.log(array2.length); // 3
console.log(array3.length); // 2
그러나 array 배열에 새로운 아이템을 추가하게 되면 array2는 array와 동일한 배열을 가리키고 있으므로 새로운 아이템이 추가된 것을 확인할 수 있으나 array3에서는 새로 추가된 아이템을 확인할 수 없다.
array3은 엄연히 아예 다른 배열(새로운 그릇)이기 때문이다.
따라서 위의 개념 때문에, 리액트에서 PureComponent를 사용하게 되었을 때 객체 안의 값만 바꾸면 안되고 업데이트해야할 일이 있다면 객체 전체를 비구조화할당을 이용해서 복사해온 후, 갱신해야할 값은 따로 적어주어야 한다.
'Front-end > Javascript' 카테고리의 다른 글
[자바스크립트/Date/날짜] 1일전, 1주일전, 1달전, 1년전 날짜 계산기 (0) | 2021.04.06 |
---|---|
event.target VS event.currentTarget (0) | 2021.03.29 |
클래스(Class) (0) | 2021.03.23 |
프로토타입(Prototype) (0) | 2021.03.23 |
[Ajax] 리팩토링 함수화 (0) | 2021.03.21 |