TIL08, JS: 변경가능 값, 변경 불가능 값 정리*

sunghoonKim·2020년 11월 25일
2

"해야할 게 너무 많다고 막막하게 느껴지는 것은, 정확하게 공부하고 있다는 증거이다."
-13기 이름모를 선배님. 땡큐 🙏

JS, Mutable & Immutable Value

자바스크립트 데이터 타입은 변경 가능 유무로 크게 2가지로 나뉜다.

변경 불가능 값 (Immutable Value)

원시 데이터 타입(boolean, null, undefined, number, string, symbol) 은 변경이 불가한 값이다. 메모리 영역에서의 변경이 불가하다는 뜻이다. 예로,

var str = "Hello";
str = "Hi";

첫번째 줄에서는 Hello 라는 값을 메모리에 생성한 뒤, str 라는 변수를 만들어 해당 메모리 주소를 가리키게 한다.
두번째 줄에서는 Hi 라는 값을 메모리에 새로 생성한 뒤, 변수가 이 새로운 주소를 가리키게 한다.
결과적으로, 메모리 상에는 HelloHi둘다 존재한다. 다만 Hello 는 현재 미아 상태일 뿐.

var user = {
  name: 'Lee',
  address: {
    city: 'Seoul'
  }
};

var myName = user.name; // 변수 myName은 string 타입이다.

user.name = 'Kim';
console.log(myName); // Lee

myName = user.name;  // 재할당
console.log(myName); // Kim

user.name = 'Kim'; 에서 user 객체의 name 값을 수정하였지만, myName 의 값은 변하지 않았다. 왜냐하면, myNameuser 객체의 name 을 가리키는게 아니기 때문이다.Lee 라는 값이 메모리에 새로 생성되었고, 이를 가리키고 있기 때문에, user 객체에서 어떠한 변화가 일어나든 무관하다.

변경 가능 값 (Mutable Value)

원시 데이터 타입을 제외한 나머지 값들은 객체로 분류되고, 객체는 모두 변경 가능한 값이다.

const numberArray = [1,2,3,4,5];
const numberArraySecond = numberArray;

numberArray.push(6);
console.log(numberArray); // [1,2,3,4,5,6]
console.log(numberArraySecond); // [1,2,3,4,5,6]

변경 불가능 값과는 다르게, 변경 가능 값을 어느 변수에 할당할 경우, 메모리에 새로이 데이터를 생성하고 변수의 포인터를 해당 주소로 가리키게 하는 것이 아닌, 기존에 존재하던 데이터의 메모리 주소를 가리키게 한다. 즉, 위의 예에서 numberArraynumberArraySecond 는 동일한 메모리 주소를 ([1,2,3,4,5] 데이터가 존재하는) 가리키고 있는 것이다. 그렇기 때문에, [1,2,3,4,5] 배열에 변화를 주었을 때, 그 변화가 두 배열에 모두 반영되었다.


JS, Shallow Copy / Deep Copy

객체는 Mutable 값으로써 여러 변수에 할당을 했을 경우, 내가 인식하지 못하는 곳에서 객체의 내용이 변하는 상황이 발생할 수 있다. 그러한 문제를 미연에 방지하려면, 할당을 할때 Immutable 값과 같이 기존 값을 복사하여 메모리에 새로 생성을 하게 하도록 하면 된다.

1. Object.assign()

const target = [];
const source = [1,2,3,4,5];

Object.assign(target, source);

console.log(target); // [1,2,3,4,5]

2. ...spread operator

const targetSecond = [...source];

console.log(targetSecond); // [1,2,3,4,5]

위 두가지 방법은 모두 얇은 복사 (shallow copy) 이다. 객체 속에 존재하는 또 다른 객체는 카피하지 않고 레퍼런스만 가져온다. 따라서, 객체속 객체에 접근하고 값을 바꿀경우, 기존 문제의 가능성이 여전히 남아있는 것이다.

객체 속의 객체 까지 카피를 하는 것을 깊은 복사 (deep copy) 라고 한다. 하지만, 기본 메소드중 deep copy를 하는 메소드는 없어서, 루프를 통해 일일이 얇은 복사를 하는 방법을 통한다. 하지만 로직을 구현하는게 너무 귀찮다면 외부 라이브러리의 힘을 빌린다. 아멘 🙏 (예로, Immutable.js 가 있다.)


JS, Object.freeze(obj);

아니면 아예 객체를 얼려버려, 내용물의 수정을 막는 방법도 있다. 마치 const 로 선언된 불변 데이터 타입과 같이 말이다. Object.freeze() 메소드는 객체 내용물의 수정을 무시시킨다.

const obj = {
  lastName: "kim",
  firstName: "sunghoon"
}

obj.lastName = "Lee"
console.log(obj.lastName) // Lee 

Object.freeze(obj);
obj.lastName = "kim"
console.log(obj.lastName); // Lee

const 타입으로 객체를 선언했지만, 여전히 속성은 수정할 수 있다. 하지만, 해당 객체를freeze 한 후에는 property 수정이 무시된다.


딥 카피를 뜨는 메소드를 내장시켜 줄 법도 한데 말이다. 귀찮았나? 🤨

0개의 댓글