React/HabitTracker

JS Object 가변성에 대해서(Spread Operator)

느리지만 꾸준하게 2021. 7. 31. 21:11

JS 오브젝트에 대해서 개념 정리

 

변수에 문자열, 숫자와 같은 원시형 데이터를 할당하게 되면 데이터 자체가 변수에 할당이 되지만, 

변수에 오브젝트를 할당하게 되면 변수에는 오브젝트가 메모리에 들어있는 주소인, 참조값이 할당된다.

num변수에 숫자 2가 들어있음

num 변수에 숫자 2 자체가 들어 있지만, numObj에는 {num: 2} 오브젝트가 메모리에 들어 있는 주소인, 참조값이, 예를 들어 주소가 x1234라고 하면 x1234가 할당되어진다.

 

즉 num에는 숫자 2가 들어 있고, numObj에는 x123 주소가 들어 있다.

 

 

만약에 오브젝트를 가리키는 변수를 다른 변수에 할당하면 어떻게 될까?

위 코드를 보면 몇 개의 오브젝트가 메모리에 생성 됐을까? => 2개이다

총 몇개의 변수가 메모리에 생성 됐을까? => 3개이다

 

코드를 위에서부터 보면

const a = { id: '1', count: 0};

id가 1인 오브젝트가 메모리에 생성되고 (참조값이 x123이라고 하면)

그 참조값이 변수 a에 할당 되어진다. 즉 a에는 x123이 들어있다.

 

const b = { id: '2', count: 0};

id가 2인 오브젝트가 메모리에 생성되고 (참조값이 x234라고 하자)

그 참조값이 변수 b에 할당이 되어진다. 즉, b에는 x234가 들어있다.

 

const c = b;

여기서는 b변수를 c에 할당하니까, b변수에 들어있던 참조값 x234가 c변수에 복사되어져서 할당이 되어진다.

즉, c변수에 b변수와 마찬가지로 x234가 들어있다.

 

정리를 해보면

const a = { id: '1', count: 0}; // x123

const b = { id: '2', count: 0}; // x234

const c = b; // x234

(메모리 주소값은 내가 임의로 설정한 값이고 실제 주소와는 다르다.)

변수에 할당된 값을을 살피면 모두 오브젝트를 가리키고 있는 참조값으 들어있고,

b와 c변수는 id가 2인 동일한 오브젝트를 가리키고 있다.

 

다른 코드를 한번 보면

 

여기서 b 변수를 이용해서 b 변수가 가리키고 있는 오브젝트의 count값을 변경하고,

b와 c 변수를 출력하면

동일한 id가 2인 그리고 count가 1인 오브젝트를 출력한다.

b와 c는 동일한 오브젝트를 가리키고 있기 때문에 b를 통해서든 c를 통해서든 오브젝트를 수정하게 되면

b와 c는 수정된 내용을 바로 적용받게 된다.

 

오브젝트는 값(value)자체가 변수에 저장되는 것이 아니라, 참조값(Reference)이 저장되기 때문이다.

그래서 오브젝트 변수를 const라고 상수 변수로 저장해 두어도, 참조값 자체는 바꿀 수 없지만

(다른오브젝트로 대체 못함)오브젝트 자체의 데이터는 수정이 가능한 이유중에 하나다.

 

또, 오브젝트 변수를 함수 인자로 전달해서 함수 안에서 오브젝트를 변경해도, 함수 밖에서 다시 오브젝트의 변경사항을 볼수 있다.

(모든 것들이 변수에는 오브젝트의 참조값이 들어 있기 때문이다.)

 

배열로 연결해서 생각해보자

여기서 생성된 오브젝트는 몇개일까? => 3개이다.

id가 1인 오브젝트 하나, id가 2인 오브젝트 하나 그리고 배열 자체의 오브젝트 하나, 총 3개의 오브젝트가 있다.

 

array[0]은 {id: '1', count: 0} 을 가리키고, 결국 arr[0]에는 id가 1인 오브젝트의 참조값이 들어있을거다.x123

array[1]은 {id: '2', count: 0} 을 가리키고, 결국 arr[1]에는 id가 2인 오브젝트의 참조값이 들어있을거다.x234

array 배열 자체가 가리키고 있는 것은 생성된 배열의 오브젝트 주소값인 x567이 될꺼다.

 

array2와 array3 각각의 변수에는 무슨 값이 할당 될건가?

바로 아래와 같이 될 것이다.

array2에는 단순히 array 변수를 할당하니까, array에 들어 있던 참조값인 x567이 그대로 할당이 된다.

즉, array와 array2는 동일한 배열 오브젝트를 가리키므로,

한쪽에는 id가 1인 오브젝트의 count를 변경해도 둘다 변경된 내용을 볼 수 있고,

한쪽에서 배열에 새로운 아이템을 추가 해도 둘다 변경된 내용을 볼 수 있다. 둘다 3개의 아이템이 들어있다.

 

그러면 array3은??

array3은 단순히 참조값을 가지고 온 것이 아니고, Spread Operator를 이용해서 array에 있는 모든 아이템들을 새로운 배열로 가지고 와서 새로운 배열을 만들게 됐다. 완전히 새로운 배열 오브젝트를 가리키는 것이다.

 

다만, 이 Spread Operator는 배열 안의 모든 오브젝트 내용들을 하나하나 복사해서 새로운 것을 만드는 것이 아니라, 오브젝트는 놔두고 array배열을 돌면서 각각의 아이템들의 참조값을 복사하게 되었다.

 

즉 array3배열안에는 array안에 들어 있는 동일한 오브젝트들이 들어있고, 배열 오브젝트 자체만 새롭게 만들어진다.

 

그래서 array3은 새롭게 만들어진 배열 오브젝트 x999 참조값이 들어있고, array3[0]에는 x123이, array3[1]에는 x234가 들어있다.

 

array에서 id가 1인 오브젝트의 count를 변경하면 셋다(array, array2, array3) 변경된 내용을 볼 수 있다.

왜냐? => 모두 배열 첫번째 요소는 참조값 x123이 가리키고 있는 id가 1인 동일한 오브젝트를 가리키고 있기 때문이다. 

 

 

대신에 array 배열에 새로운 아이템을 추가하면 array2는 array와 동일한 배열을 가리키고 있으며 새로운 아이템이 추가된걸 확인할 수 있지만, array3에서는 새로 추가된 아이템을 볼 수 없다. array3는 새로운, 엄연히 다른 배열 오브젝트(물건을 담고 있는 껍데기, 컨테이너)이기 때문이다.

 

마지막으로!! ...=> 이거 spread operator은 Shallow-coding을 한다.

배열안에 있는 모든 오브젝트 또 그 안에 들어 있을 수 있는 오브젝트들까지 모두 다 한땀 한땀씩 새로운 것으로 바꿔 주는 것은 아니고, 심플하게 제일 상위의 배열 껍데기만 새로운 껍데기로 바꿔주고 안의 오브젝트는 예전의 참조값을 복사해 온다

 

spread operator를 이용하면 처음에 안에 있는 내용물들을 복사하지만,(값이 아니고 레퍼런스, 참조값만 복사!!)

배열 자체는 새로운 것을 만들어서 배열에 아이템을 삭제 하거나, 추가 하면 배열의 내용은 달라진다.

 

 

 

 

 

 

<출처 : DreamCoding 리액트 개념 정리+유튜브 클론코딩: ellie>

참고: https://academy.dream-coding.com/courses/react-basic

 

리액트 강의 (유튜브 클론 코딩 + 실시간 전송 명함 카드 만들기 웹앱 만들기)

리액트 전반적인 개념 설명과 (클래스 컴포넌트와 함수 컴포넌트 그리고 리액트 훅까지) 실전 유튜브 클론 코딩 프로젝트. Firebas의 실시간 데이터베이스를 이용해 멋진 명함 카드 만들기 웹 어

academy.dream-coding.com