Iriton's log

0. JavaScript Immutability 본문

Frontend/Study

0. JavaScript Immutability

Iriton 2024. 10. 16. 18:44

스터디 참고 자료

https://youtube.com/playlist?list=PLuHgQVnccGMBxNK38TqfBWk-QpEI7UkY8&si=l0cktZbzZIUvhKWS

 

JavaScript Immutability

 

www.youtube.com

 

 

 

불변성이란 데이터 원본이 훼손되는 것을 막는 것이다.

데이터를 불변하게 다루면 데이터들 간의 간섭으로 인한 버그의 가능성을 획기적으로 낮출 수 있다.

또, 데이터가 변경되었는지 여부를 쉽게 체크할 수 있으며 특히 CRUD(Create, Read, Update, Delete) 작업 시, 불변성을 보장하는 것이 매우 중요하다.

 

 

이름에 대한 불변함

const를 사용하여 이름을 불변하게 만든다.

const를 사용하게 되면 선언한 변수를 수정할 수 없게 되며, 수정을 시도하는 경우 error를 발생시킨다. (var을 사용할 경우 error가 발생하지 않고 시스템 크기에 따라 크고 작은 버그들이 발생하여 시스템이 잘 작동하지 않게 될 수 있다.)

 

 

변수 할당 방식 비교

JavaScript는 값이 바뀌지 않는 원시 데이터 타입과 값이 바뀔 수 있는 객체 타입을 다르게 취급한다.

  • 원시 데이터 타입(Primitive): Number, String, Boolean, Null, Undefined, Symbol…
  • 객체 타입(Object): Object, Array, Funcfion…

원시 데이터 타입의 경우 다른 변수여도 같은 값을 가진다면 같은 메모리 위치를 가리키기에 비교 연산 === 를 했을 때 true가 나오지만 객체 타입의 경우에는 아무리 같은 값을 가진다 해도 다른 메모리에 위치하기 때문에 false가 나오게 된다.

 

 

객체의 가변성

원시 데이터 타입은 같은 값을 가질 땐 같은 위치를 가리키다가 하나의 변수가 다른 값을 가지게 된다면 그때부터는 다른 공간에 값을 넣고 그 위치를 가리키게 된다.

객체 타입은 var o1 = {name: ‘kim’}; var o2=o1; 로 두고 o2.name=’lee’ 를 대입하면 새 메모리 공간을 가리키게 되는 것이 아니라 기존 공간에 있던 데이터가 변경되는 것이다.

 

 

객체의 복사

Object.assign( {}, o1 )을 통해서 빈 객체와 o1이란 이름을 가진 객체를 병합하여 하나의 객체로 만들게 되면 o1과 같은 값을 복사해서 다른 위치에 저장한다. 따라서 해당 객체 이름이 o2라 했을 때 o2.name=’lee’; 코드를 실행하면 o1의 값은 변하지 않고 o2가 가리키는 메모리 상의 데이터만 변경된다.

 

 

중첩된 객체의 복사

원시 데이터 타입인 string과 달리 배열 score는 별도의 공간에 저장되고 그 공간을 가리키게 된다.

이때, 객체를 복사하게 되면 원시 데이터 타입의 값은 복사되어 별도의 공간에 저장되지만 배열은 별도 공간에 복사되는 것이 아니라 똑같은 공간을 가리키게 된다.(포인터가 복사되는 것이라 생각하면 될 것 같다.)

따라서, 복사된 객체의 배열에 push를 하게 되면 원본 데이터에도 영향이 간다.

해결하는 방법은 아래와 같다.

 

배열을 복사하는 함수(concat 등등)을 사용하여 원본 데이터를 복사하여 별도의 공간에 저장해야 한다.

 

불변의 함수

function fn(person){
	person.name = 'lee';
}
var o1 = {name: 'kim'}
fn(o1);
console.log(o1);

위 코드를 실행하면 원본 데이터인 o1.name이 kim이 날라가고 lee가 될 것이다.

원본 데이터를 불변하게 유지하는 함수는 아래와 같이 작성해야 한다.

function fn(person){
	person = Object.assign({}, person};
	person.name = 'lee';
	return person;
}
var o1 = {name: 'kim'}
var o2 = fn(o1);
console.log(o1, o2);

그럼 새로운 o2가 생성되면서 원본 데이터는 바뀌지 않고 원하는 값을 출력할 수 있다.

function fn(person){
	person.name = 'lee';
}
var o1 = {name: 'kim'}
var o2 = Object.assign({}, o1);
fn(o2);
console.log(o1, o2);

위 코드도 같은 결과가 나온다.

 

 

Object freeze로 객체를 불변하게 만들기

var o1 = {name:'kim', score:[1,2]}
Object.freeze(o1);
o1.name='lee';
console.log(o1);

위 코드를 실행하면 freeze 함수로 인해 원본 데이터가 바뀌지 않고 o1이 출력되는 것을 확인할 수 있다.

근데 주의할 점은 한 번 freeze 한 것을 푸는 방법은 없다. 복제를 해서 써야 한다.

또 유의할 점은 score에 push를 할 경우엔 원본 데이터가 변경이 된다.

이유는 score 배열은 원시 데이터 타입이 아니라서 별도의 공간에 저장되기 때문이다.

따라서 Object.freeze(o1.score); 코드를 추가해야지 오류가 뜨면서 push 하지 못한다고 뜬다.

 

 

const vs Object.freeze

const는 가리키는 주소 자체를 바꾸지 못하는 것

freeze는 값 자체를 변경하지 못하게 하는 것

Comments