ES6의 불변 변수 사용법

봄·2025년 2월 6일

💙 React 파보기

목록 보기
1/4
post-thumbnail

ES6에서는 const 키워드를 사용하여 불변 변수(Immutable Variable)를 선언할 수 있다.

하지만 여기서 중요한 점은

"불변 변수는 값을 다시 할당할 수 없지만, 내부 값을 변경할 수는 있다"는 것이다.

이 말이 조금 헷갈릴 수 있는데, 하나씩 알아보자.


불변 변수와 무결성 제약 조건

책에서는 불변 변수는 값을 직접 수정할 수 없지만, 객체나 배열의 내장 함수를 사용하면 내부 값을 변경할 수 있다고 설명하고 있다.

그러나 이런 방식은 무결성 제약 조건(Invariant Constraint)에 위배된다고 한다.

📌 무결성 제약 조건이란?

  • 원본 데이터를 직접 수정하면 예상치 못한 동작이 발생할 가능성이 크다.
  • 따라서, 원본 데이터를 유지하면서 새로운 변수를 생성하여 새로운 값을 할당해야 한다.
  • 즉, "수정"하는 것이 아니라, 새로운 변수를 만들어 "새롭게 정의"해야 한다.

"불변 변수를 새로 만들어 할당해야 한다"는 뜻

❌ 잘못된 방법 (원본 데이터 변경 - 무결성 위배)

const person = { name: "Alice", age: 25 };

// 원본 데이터를 직접 수정하면 무결성 제약 조건에 위배됨
person.age = 30;

console.log(person); // { name: "Alice", age: 30 }

🚨 여기서 문제점

  • const로 선언했지만, 객체 내부의 속성은 여전히 변경할 수 있다.
  • 원본 데이터를 직접 수정하면 예측 불가능한 문제가 발생할 수 있다.

✅ 올바른 방법 (새로운 변수로 새로운 객체 생성)

const person = { name: "Alice", age: 25 };

// 기존 객체를 유지하면서 새로운 객체 생성
const updatedPerson = { ...person, age: 30 };

console.log(person);        // { name: "Alice", age: 25 } (원본 유지)
console.log(updatedPerson); // { name: "Alice", age: 30 } (새로운 객체)

📌 이렇게 하면 원본 데이터를 변경하지 않고 새로운 객체를 생성하여 적용할 수 있다!

📌 이 방식이 바로 불변성을 유지하면서 값을 변경하는 올바른 방법이다.


왜 이렇게 해야 할까?

✅ 1) 상태 변화 추적이 쉬워진다.

  • 원본 데이터를 직접 수정하면 언제, 어디서 바뀌었는지 추적하기 어렵다.
  • 반면, 새로운 데이터를 만들면 변경된 부분을 쉽게 파악할 수 있다.

✅ 2) 예측 가능성이 높아지고 버그를 방지할 수 있다.

  • 원본 데이터를 직접 수정하면, 예상치 못한 동작이 발생할 수 있다.
  • 불변성을 유지하면 코드의 안정성이 높아진다.

✅ 3) React에서 상태 관리를 위해 필수적이다.

  • React에서 useState, useReducer를 사용할 때, 불변성을 유지해야 상태 변경을 감지하고 리렌더링을 정상적으로 수행할 수 있다.
  • 원본 데이터를 직접 수정하면 변경 사항이 감지되지 않아 UI가 정상적으로 업데이트되지 않을 수 있다.

불변성을 유지하면서 배열 수정하기

📌 기존 데이터를 직접 수정하지 않고, 새로운 데이터를 생성하는 방식을 사용해야 한다.

📌 이를 위해 가변 내장 함수(Mutable Methods) 대신 무결성 내장 함수(Immutable Methods)를 사용해야 한다.

가변 내장 함수 vs. 무결성 내장 함수 정리

가변 내장 함수 (원본 변경 🚨)무결성 내장 함수 (새로운 값 반환 ✅)
push(...items) (값 추가)concat(...items)
splice(s, c, ...items) (특정 위치 변경)slice(0, s).concat(...items, slice(s+c))
pop() (마지막 요소 제거)slice(0, len - 1)
shift() (첫 번째 요소 제거)slice(1)

1️⃣ 가변 내장 함수 (원본을 직접 변경하는 방법 - ❌ 권장하지 않음)

const arr = [1, 2, 3];

arr.push(4); // 🚨 원본 배열이 변경됨
console.log(arr); // [1, 2, 3, 4]

arr.pop(); // 🚨 원본 배열이 변경됨
console.log(arr); // [1, 2, 3]

❌ push(), pop() 같은 가변 내장 함수는 원본 배열을 직접 수정하므로 불변성을 깨뜨린다.

❌ 이런 방식은 React 같은 라이브러리에서 상태 관리할 때 문제가 될 수 있다.


2️⃣ 무결성 내장 함수 (새로운 배열을 반환하는 방법 - ✅ 추천)

const arr = [1, 2, 3];

// ❌ 가변 함수 대신 ✅ 무결성 함수 사용!
const newArr = arr.concat(4); // 새로운 배열 반환
console.log(arr); // [1, 2, 3] (원본 유지)
console.log(newArr); // [1, 2, 3, 4] (새로운 배열)

✅ concat(), slice() 같은 무결성 내장 함수를 사용하면 원본을 변경하지 않고 새로운 배열을 반환할 수 있다!

✅ 이런 방식이 불변성을 유지하면서 데이터를 다루는 올바른 방법이다.


객체에서도 동일한 개념 적용

배열뿐만 아니라 객체(Object)도 원본을 변경하지 않고 새로운 객체를 만들어야 한다.

❌ 가변 방식 (원본 변경 🚨)

const person = { name: "Alice", age: 25 };

// 원본 객체를 직접 수정 ❌
person.age = 30;

console.log(person); // { name: "Alice", age: 30 } (원본이 바뀜)

👉 이 방식은 원본 데이터를 직접 수정해서 불변성을 깨뜨린다.


✅ 무결성 방식 (새로운 객체 반환 ✅)

const person = { name: "Alice", age: 25 };

// 기존 객체를 유지하고 새로운 객체 생성
const newPerson = { ...person, age: 30 };

console.log(person); // { name: "Alice", age: 25 } (원본 유지)
console.log(newPerson); // { name: "Alice", age: 30 } (새로운 객체)

✅ ...spread 연산자를 사용하면 기존 객체를 복사하고 변경할 속성만 수정할 수 있다.

✅ 이 방식이 무결성을 유지하는 올바른 방법이다.


결론

📌 무결성을 유지하는 것이 중요하다.

  • 배열을 변경할 때 push(), pop() 대신 concat(), slice() 사용!
  • 객체를 변경할 때 ...spread 연산자 사용!
  • 원본 데이터를 직접 수정하는 방식 ❌
  • 새로운 배열 또는 새로운 객체를 만들어 수정 ✅

📌 실제로 React, Redux 같은 라이브러리에서는 불변성이 필수!

  • 불변성이 깨지면 상태 변화 감지가 어려워지고, 예측하지 못한 버그가 발생할 수 있다.

📌 한 줄 요약

✅ 배열이나 객체를 변경할 때, 원본을 직접 수정하지 말고 새로운 값을 만들어 사용하자!

✅ 무결성 내장 함수를 활용하면 불변성을 유지하면서 안전하게 데이터를 다룰 수 있다. 🚀

profile
FE 개발 꿈틀이

0개의 댓글