JS - 불변성 (ps. React에서 불변성)

김정인·2022년 12월 13일
0

JavaScript

목록 보기
4/6
post-thumbnail

📌JavaScript에서 불변성


JavaScript에서 객체는 참조 형태로 값을 주고 받는데, 하나의 객체가 생성되고 그 값을 다른 객체들이 참조하고 있다면 의도하지 않은 값의 변형으로 사이드이펙트가 발생하는 경우가 있을 수 있습니다. 보통 이런 경우 래퍼런스를 참조한 다른 객체를 변경하기 때문입니다. 이와 같은 문제를 방지하기 위해서는 불변의(Immutable) 객체를 만들거나 객체 복사를 통해 새로운 객체를 생성한 후 변경하는 것이 안전합니다.

이를 더 자세하게 살펴보기 위해서는 JavaScript의 원시값과 참조값의 차이점을 알아야합니다.
아래 간단한 예시가 있습니다.

/* ex1) */
let numA = 10;
let numB = numA;
numA = 20;
console.log(numA,numB); // 20 10

/* ex2) */
let arrA = [1,2,3];
let arrB = arrA;
arrA.push(4);
console.log(arrA,arrB); // [ 1, 2, 3, 4 ] [ 1, 2, 3, 4 ]
  • ex1) 코드는 변수 numA에 10을 할당하고, 변수 numB는 numA가 가리키는 주소를 가리킵니다. 이때 a를 20으로 변경하면 numA와 numB 모두 20이 아닌 numA만 20으로 바뀌게 됩니다.

  • ex2) 코드는 변수 arrA에 값을 할당하고, 변수 arrB는 arrA가 가리키는 주소를 가리킵니다.
    이때 arrA에 값을 변경하면 arrA, arrB 모두 값이 바뀌게 됩니다.



📌원시값과 참조값의 차이점


  • 원시값, 원시 타입 : string, number, boolean, null, undefined, symbol

    • 원시값은 변경 불가능한 값입니다. 한 번 생성된 원시값은 읽기 전용으로 그 값을 변경할 수 없습니다.

    • 원시값은 변수에 할당하면 변수에는 실제 값이 저장됩니다.

    • 변경 불가능한 값이란 재할당을 못한다는 것이 아닌 재할당을 하면 새로운 메모리 공간을 확보하여 값을 넣어준다는 것을 의미합니다.

  • 참조값, 객체 타입 : Array, Object, Function

    • 참조값은 변경 가능한 값입니다. (불변성 주의!)
    • 참조값은 변수에 할당하면 변수에는 참조값(메모리 주소)이 저장됩니다.
    • 변경 가능한 값이란 메모리 재할당없이 직접적으로 객체에 접근하여 프로퍼티를 동적으로 추가, 갱신, 삭제가 가능하다라는 것을 의미합니다.

🤔 값에 의한 전달(pass by value) vs 참조에 의한 전달(pass by reference)

  • 원시타입은 값이 복사되어 전달된다고 했습니다. 이것을 값에 의한 전달이라고 합니다.

    아래와 같이 copyNum에 numA를 할당하면 값 1이 복사되어 전달되고, numA와 copyNum의 값 1은 다른 메모리 공간에 저장된 값입니다. 따라서 numA와 copyNum은 별개의 메모리에 할당되어 있기 때문에 numA 값을 변경해도 copyNum에는 영향을 주지 않습니다.

let numA = 1;
let copyNum = numA;
console.log(numA === copyNum); // true

numA = 10;
console.log(numA === copyNum); // false

  • 참조타입은 실제 값이 아닌 참조값이 전달된다고 했습니다. 즉 참조값이 저장된 메모리 주소가 전될되는데 이것을 참조에 의한 전달이라고합니다.

    아래와 같이 copyNum에 numA를 복사하면 {value:1} 객체가 저장된 메모리의 주소를 같이 공유하는 상태가 되기때문에 numA의 value를 변경하면 copyNum의 값도 변하게 됩니다.

let numA = {
	value : 1
};
let copyNum = numA;
console.log(numA.value === copyNum.value); // true

numA.value = 10;
console.log(numA === copyNum); // true


📌React에서의 불변성이 중요한 이유


JavaScript 라이브러리의 하나로서 사용자 인터페이스를 만들기 위해 사용하는 React에서도 불변성이 중요합니다. 그 이유는 React의 브라우저 렌더링 과정과 관련이 있는데, 간략하게 요약하자면 React는 가상돔을 사용하여 바뀐 부분을 찾는 과정 Diffing, 바뀐 부분만 실제 돔에 적용시키는 Reconciliation을 통해 렌더링을 합니다. 이때 Diffing과정에서 이전 객체와 현재 객체를 얕은 비교를 통해 변화를 판단하기 때문에 불변성의 유지가 중요합니다.

🤔 얕은 비교는 뭐야..

  • 얕은 비교란 원시타입은 값이 동일한지만 비교하고, 참조타입은 값이 아닌 래퍼런스(참조 위치, 주소)를 비교하는 것을 말합니다.

  • 따라서 참조타입 state를 직접 변경하게 되면 값은 바뀌지만 참조값이 바뀌지 않아 렌더링이 일어나지 않는 현상이 발생합니다.

그렇다면 불변성을 어떻게 지킬까요 ?

  1. 스프레드 문법 사용
  2. map, filter, slice, reduce 와 같은 새로운 배열을 반환하는 메서드 사용
  3. Object 메서드 사용
  4. 라이브러리 사용 (Immutable, Immer ..)

등과 같은 여러가지 방법이 있습니다. 예시까지 첨부하면 글이 너무 길어질 것 같아, 간략한 예시를 확인하고 싶으신 분들은 제가 이전 티스토리에 정리해둔 글을 참고해주시면 감사하겠습니다 :)

이전 티스토리 - 불변성 정리글

profile
FE 개발자

0개의 댓글