본문 바로가기

FE/Vanilla

배열을 const 로 선언했을 때, 왜 push와 pop이 가능할까 (state 배열)

갑자기 궁금해짐

조만간 알아보도록 하자

 

대체 언제 옴?


알아보러 왔다. 우선 const 가 무엇인지에 대해 알아보자

const 선언은 블록 범위의 상수를 선언합니다. 상수의 값은 재할당할 수 없으며 다시 선언할 수도 없습니다.

 

간단한 답변은 push 와 pop 행위가 재할당/재선언이 아니기 때문이다. (not re-assigning or re-declaring)

[ https://stackoverflow.com/questions/23436437/why-can-i-change-a-constant-object-in-javascript ]

 

const a = [];
a.push('hihi');	// works

const b = [];
b = ['hihi'];	// error

const b = ['hihi'];	// error

위와같은 코드는 차례대로 
메소드 사용, 재할당, 재선언이다. 따라서 1번째 문단의 코드만 정상작동한다.

 

 

아니 그래서 push 와 pop 은 재할당 이 왜 아닌데?

 

라고 할까봐 나무위키를 들고 왔다 [ https://namu.wiki/w/JavaScript#s-4 ]

객체의 경우 상수로 선언해도 메모리값만 상수일 뿐 객체 안의 내용은 변경이 가능하다. 즉 객체가 저장된 공간을 가리키는 정보만 상수일뿐 그 객체의 정보 자체는 변경이 가능하다. 이런 이유로 JavaScript에서 객체는 변수로 선언할 이유가 없으며 거의 모든 케이스에서 상수로 선언하는게 일반적이다. 또 이렇게 상수로 선언된 객체의 Immutability를 보장하기 위해 여러 테크닉이 쓰이게 되는데 주로 ES6에서 도입된 Spread Operator를 사용하는 것이 일반적이다. 이렇게 객체를 복사하여 사용할 때도 Deep clone하지 않으면 의도치 않게 원본 객체가 변경되어버리기 때문에 많은 주의가 필요하다.

 

아 .. 배열을 선언한 것은 포인터이다.

 

const a = []; 를 통해서 a 에 배열의 포인터를 지정한 것이고,
a.push(); 를 통해 a 의 메모리에 접근한다. 
push(), pop() 등의 메소드는 포인터를 바꾸는 행위가 아니기 때문에 push(), pop() 이 가능한 것이다.

 

배열 말고도 객체에서도 동일한 로직으로 접근 가능하다.

 

 근데 애초에 이게 왜 궁금함? 변태아님?

 

그런 것 같기도 하다. 

 

어디에 써먹을 수 있음?

 

React 에서 객체 혹은 배열을 useState 로 지정하였을 때,
객체 혹은 배열 안의 값이 바뀌어도 hook 이 catch 하지 못하는 현상이 있었다.
[ https://morohaji.tistory.com/56?category=938496 ]

const [amountCount, setAmountCount] = useState([1]);

if (state[index] - 1 > min) {
  setState((state) => state[index] -1);
}

그래서 검색해보니 아래와 같은 코드로 짜야한다고 하여

const [amountCount, setAmountCount] = useState([1]);

if (state[index] - 1 > min) {
  const localState = [...state];
  localState[index] -= 1;
  setState(localState);
}

이렇게 하여 해결한 경험이 있었다.

 

지금 생각해보니 state 에 저장된 값은 단순한 포인터였고,

배열 안의 값을 변경해도 포인터는 변하지 않기 때문에 

hook 이 catch 할 수 없지 않았을까 ..

그래서 spread operator 를 통해 포인터 위치를 바꿔줌으로써 hook 에게 변경을 알리게 되었고 해결한게 아닐까 싶다

 

오 .. 신기하기는 한데, 메모리 관리는 어케함?

 

나도 잘 모르겠다. 조만간 알아보도록 하자. [ https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management#reference-counting_garbage_collection ]