[F-Lab 모각코 챌린지 55일차] Immutability 불변성

Nami·2023년 7월 25일
0

66일 포스팅 챌린지

목록 보기
55/66

챌린지 내내 비슷한 주제를 계속 맴도는 것 같은 기분이었다. 그런데도 모든 걸 이해하지 못하는 상태의 연속. 모든 것이 연관되어있어서 점점 범위를 확장시키고 깊이있게 알게 되어 총 정리를 하고 싶은 마음이 생긴다. 같은 주제라도 5월 말, 코어자바스크립트로 불변성에 대해 읽었을 때와 현재의 나는 시각이 달라졌을테니 말이다. 달리는 법을 배우고 호흡법을 배우다, 혼자 뛰어보며 복기하다 체화한 것마냥 말이다. 결국 같은 것이지만 퀄리티는 달라진게 느껴진다. 물론 깊이도 주제별로 제각각이라 아직 역부족인 게 대부분이지만 꾸준함이 답이라 믿는다.
상태, 데이터 타입, 데이터 할당 등. 이미 다뤘던 것이지만 이전의 코어 자바스크립트를 볼 때보다 훨씬 이해가 잘되어서 좀 더 확실히 다뤄보았다.


Immutability 불변성

상태를 변경하지 않는 것.

불변성을 얘기하면 언급되는 것으로는 순수 함수, 함수형 프로그래밍이 있다. 함수형 프로그래밍은 이전에 정리했으므로 순수 함수만 알아보겠다.

순수함수 Pure function

A pure function in JavaScript is a function that returns the same result if the same arguments(input) are passed in the function.

  1. 동일한 인자input에는 항상 동일한 결과를 내는 함수.
  2. 함수 외부의 상태를 변경하거나, 외부의 상태에 영향을 받아서는 안된다.

이 두개를 아우르는 순수 함수에 대한 근본적인 정의는 무엇일까?
근본적으로 보았을 때 순수 함수는 그냥 수학적 함수다.

수학적 함수
수학적 함수는 특정한 input(arguments)을 받아서 그에 해당하는 output(result)을 반환하는 관계를 나타내는 규칙이다. 외부 상태에 의존하지 않으며, 동일한 입력에 대해 항상 동일한 출력을 내보낸다. 수학적 함수는 부작용 없이 입력과 출력만으로 정의되며, 함수 자체가 외부에 영향을 끼치지 않는다.

순수 함수는 이러한 수학적 함수의 개념을 프로그래밍에 적용한 것이다!

프로그래밍의 세계에는 무언가를 저장하고 변경하고 불러올 수 있는 상태라는 개념이 존재하지만, 수학의 세계에는 그런 개념이 없기 때문에 모든 함수는 함수 외부의 무언가에 절대 영향을 받지 않고 독립적으로 존재한다.

그렇기 때문에 상태State라는 개념 자체가 존재하지 않는 수학의 함수를 프로그래밍으로 구현한 모델인 순수 함수 또한 함수 외부의 상태에 영향을 받지 않아야한다는 규칙을 가질 수 밖에 없는 것이다.

하지만 사용자의 요구사항, 시간의 흐름 등으로 인한 변화 속에서 소프트웨어의 상태가 변하지 않을리 없다.

상태가 시간의 흐름에 따라 변하는 값이라면, 불변성은 정확히 어떤걸까?
변하지 않을 수 없는데 불변하는 성질이 존재할까?
정답은 이전에 공부한 코어 자바스크립트 데이터 타입 단원에 있었다!

변수로 메모리에 접근

변수 선언과 데이터 할당

let a; // 변수를 만든다. 식별자는 a로 한다.
a = 1; // 변수 a에 데이터 할당

console.log(a); // 1;

변수란 결국 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇, 메모리에 저장되어 있는 어떠한 값에 접근하는 일종의 단축어같은 개념이며, 만약 변수가 없다면 우리는 일일히 0x0018fa와 같은 메모리 주소를 사용하여 메모리에 값을 저장할 공간을 마련하고 값을 저장하거나 접근해야한다는 것.

데이터 저장 방식

원시 값을 변수에 할당하면 (확보된 메모리 공간) 실제 값이 저장된다. 객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장된다.

엄밀히 따지면 자바스크립트의 모든 데이터 타입은 참조형 데이터일 수 밖에 없다. 다만 기본형은 주솟값을 복사하는 과정이 한 번만 이뤄지고, 참조형은 한 단계를 더 거치게 된다는 차이가 있다.

  • 원시 타입 : 콜스택의 value에 변수 값이 저장
  • 참조 타입 : 메모리 힙의 주소가 콜스택의 value에 저장, 참조타입 변수의 값은 메모리의 value에 저장

변수 할당, 재할당

원시 타입



원시타입의 데이터 값은 콜스택에 저장되고, 데이터 값이 저장된 콜스택의 주소값은 변수 a, b에 각각 저장된다.
(변수 a, b 식별자 자체는 실행컨텍스트의 렉시컬 환경에 저장된다.)

변수 a에 20을 재할당하면, 본인의 메모리에 있는 값을 변경하는게 아니라, 기존에 20을 저장하고 있는 메모리의 주소값으로 교체한다.
a에 저장된 주소값은 20을 가리키고 있던 b에 저장된 주소값과 동일해진다.

변수 b에 30을 재할당하면, 변수 b의 주소값이 가리키는 메모리에 저장된 20을 30으로 교체하는게 아니라, 새로운 메모리를 확보하여 30을 저장하고, 변수 b에 저장된 주소값을 해당 주소값으로 교체한다.

참조 타입


배열과 같은 참조 타입 데이터는 메모리 힙에 저장된다.
메모리 힙의 주소값은 콜 스택에 저장되고, a와 b에는 해당 콜스택의 주소값이 각각 저장된다. (a는 const로, b는 let으로 선언됨)

변수에 값을 재할당한 것이 아니라 변수에 저장된 데이터를 수정했다. 메모리 힙에 저장된 배열의 값을 변경해도 배열이 저장된 메모리 힙의 주소는 그대로다.
즉, 콜 스택에 저장된 메모리 힙의 주소는 변경되지 않는다.
따라서 변수 a와 b에 저장된 주소값도 변하지 않는다.

let

let으로 선언된 b에 다른 배열을 할당하고 있다.
메모리 힙에 새로운 주소가 확보되고, 새로운 배열이 저장된다.
콜스택에 저장되는 메모리힙의 주소값도 새로운 주소로 변경이 필요하다.
이때 콜스택도 기존에 저장되어 있던 주소값을 바꾸는게 아니라, 새로운 메모리를 확보해서 새로운 메모리힙의 주소값을 저장한다. 따라서 변수 b에 저장되는 콜스택의 주소값도 변경된다.

참조타입은 동일한 구성의 객체를 생성하더라도, 매번 새 메모리를 확보하여 새 객체를 생성한다.

const

const로 선언된 a에 다른 배열을 할당을 할당하면 에러가 난다.
메모리힙에 새로운 공간을 확보해 다른 배열을 저장하면, 콜스택에서도 새로운 메모리를 확보해 해당 메모리힙의 주소를 저장해야하는데,
이는 결과적으로 const로 선언된 a에 저장된 콜스택의 주소값도 변경하게 만든다.

const로 선언된 변수는 본인에게 할당된 콜스택 주소값의 변경을 허용하지 않는다.
(이것이 const의 정확한 의미가 아닐까 한다. 그래서 const로 선언된 변수는 반드시 초기값을 할당하면서 선언해야 한다.) 따라서 이 코드는 실행이 불가능하다.

원시 값이 불변성을 유지한다는 것은 단순히 '함수의 인자를 변경하지 않는다', '변수를 재할당하지 않는다'는 개념이 아니라, 포인트는 메모리에 이미 담긴 값을 변경하지 않는 것이다.

똑같이 함수 내부에서 인자를 수정하는 행위더라도 값에 의한 호출 방식을 사용하는 자료형인지 참조에 의한 호출 방식을 사용하는 자료형인지에 따라 결과는 큰 차이가 나기 때문에, 불변성을 지키기 위해선 항상 염두 해야한다.

불변성의 진짜 의미는 메모리 영역에서 값이 변하지 않는다라는 의미인 것을 확실히 깨달았다. 즉, 원시 타입의 원본 데이터는 변경될 일이 없다는 것, 원본을 참조하는 다른 객체에서 오류를 발생하지 않게 한다는 것.

이 부분을 정리하게 되어 코어 자바스크립트를 좀 더 쉽게 볼 수 있을 것 같다.
추가로 알게되는 부분은 추가하겠다.


0개의 댓글