javascript object freeze로 불변 객체 만들기: 개념과 실무 적용
javascript object freeze를 사용해 객체 불변성을 확보하는 방법과 실무 예제, 깊은 동결 접근법, 성능·보안 고려사항, 적용 체크리스트까지 실무 중심으로 정리합니다.
javascript object freeze이 필요한 상황
javascript object freeze는 런타임에서 객체의 속성을 변경하지 못하도록 잠글 때 사용하는 네이티브 방법입니다. 이 글에서는 javascript object freeze를 통해 어떤 이점을 얻을 수 있는지, 실무에서 어떻게 적용하는지, 그리고 깊은 동결과 관련된 구현 및 주의점을 모두 다룹니다. 독자는 이 글을 통해 불변 객체를 만들고 유지하는 실무 코드 예제, 판단 기준 표, 체크리스트를 얻어 바로 적용할 수 있습니다.
javascript object freeze 핵심 개념
Object.freeze(obj)는 객체의 기존 속성을 변경할 수 없게 만들고, 속성 추가·삭제를 막습니다. 단, 얕은(freezing is shallow) 동결이므로 중첩된 객체 내부는 그대로 변경될 수 있습니다. 또한, non-strict 모드에서는 변경 시 에러가 발생하지 않지만 실패합니다. strict 모드에서는 TypeError가 발생할 수 있습니다.
주요 포인트:
- 얕은 동결: 최상위 속성만 고정
- 속성 속성값이 객체인 경우 내부 변경은 가능
- 프로토타입 변경은 막지 않음(객체의 프로토타입을 수정하면 동작이 영향을 받을 수 있음)
javascript object freeze 실무 예제
간단한 사용 예제:
// 예제: 얕은 동결 const config = { apiUrl: 'https://api.example.com', retries: 3 }; Object.freeze(config); config.retries = 5; // 변경되지 않음 (strict 모드 아님) console.log(config.retries); // 3 // 중첩 객체의 문제 const state = { user: { name: 'Alice' } }; Object.freeze(state); state.user.name = 'Bob'; // 가능: 얕은 동결 console.log(state.user.name); // Bob
깊은 동결 유틸 구현 예제:
// deepFreeze 함수: 순환 참조는 간단히 처리(visited Set 사용) function deepFreeze(obj, visited = new Set()) { if (obj === null || typeof obj !== 'object') return obj; if (visited.has(obj)) return obj; visited.add(obj); Object.getOwnPropertyNames(obj).forEach((prop) => { const value = obj[prop]; if (typeof value === 'object' && value !== null) { deepFreeze(value, visited); } }); return Object.freeze(obj); } const nested = { a: { b: { c: 1 } } }; deepFreeze(nested); nested.a.b.c = 2; // 변경되지 않음 console.log(nested.a.b.c); // 1
언제 쓰면 좋고 언제 피해야 할까
언제 쓰면 좋은가:
- 공유 상태를 외부 변경으로부터 보호하고 싶을 때
- 라이브러리/공용 설정 객체를 안전하게 노출할 때
- 간단한 불변성 보장을 통해 디버깅과 추적을 쉽게 하고 싶을 때
언제 피해야 할까:
- 객체가 매우 크고 깊은 구조라 성능 오버헤드가 우려될 때
- 빈번한 변경이 필요한 상태(예: 빈번히 업데이트되는 로컬 상태)
- 프레임워크나 라이브러리(특히 렌더러 내부)에서 내부 최적화를 방해할 수 있는 경우
판단 기준 표
| 구분 | 항목1 | 항목2 | 항목3 |
|---|---|---|---|
| 내용 | 간단한 설정 객체 | 공유 읽기 전용 데이터 | 깊은 중첩 상태에는 주의 |
실무 적용 팁과 패턴
- 작은 설정 객체에 Object.freeze를 사용하고, 애플리케이션 상태는 불변 라이브러리(예: Immer, Immutable.js)로 관리.
- API 응답을 바로 freeze하지 말고, 필요한 필드만 추출 후 freeze.
- 테스트에서 내부를 조작해야 하는 경우를 대비해 테스트 전용 훅으로 복제해서 사용.
성능·보안·운영 주의점
성능:
- Object.freeze는 객체의 속성을 잠그는 작업으로 큰 객체나 많은 객체에 반복 적용하면 비용 발생.
- deepFreeze는 재귀 탐색로직 때문에 순환 참조 처리 및 성능 최적화 필요.
보안:
- Object.freeze는 런타임에서 변경을 방지하지만, 클라이언트 측에서 완전한 보안 수단은 아님. 민감 데이터는 서버에서 보호해야 함.
운영:
- 프로덕션 소스맵 혹은 디버그 로그에서 freeze로 발생한 TypeError가 발생할 수 있으니 에러 핸들링을 설계할 것.
실무 체크리스트
- 객체가 읽기 전용이어야 하는가 판단
- 객체 크기(깊이)와 빈도(동결 호출 횟수) 평가
- deepFreeze 필요한 경우 순환 참조 처리 설계
- 테스트에서의 복제/모킹 방안 준비
- 프레임워크/라이브러리 호환성 확인
javascript object freeze 적용 비교 표
| 구분 | 사용 이유 | 장점 | 단점 |
|---|---|---|---|
| Object.freeze | 간단한 얕은 불변성 필요 | 네이티브, 간단 사용 | 중첩 객체는 보호 안 됨 |
| deepFreeze(유틸) | 중첩 객체 불변성 필요 | 모든 중첩 잠금 가능 | 성능 비용, 순환 처리 필요 |
| Immer/Immutable | 복잡한 상태 관리 | 편의성, 성능 최적화 옵션 | 러닝커브, 의존성 추가 |
자주 묻는 질문
Q1: Object.freeze가 완전한 불변성을 보장하나요? A1: 아니요. Object.freeze는 얕은 동결이라 중첩된 객체는 여전히 변경될 수 있습니다. 완전한 불변성이 필요하면 deepFreeze나 불변성 라이브러리를 고려하세요.
Q2: Object.freeze한 객체를 JSON.stringify하면 문제가 있나요? A2: 아닙니다. Object.freeze는 직렬화에 영향을 주지 않습니다. 다만 함수나 심볼 같은 직렬화 불가능한 값은 원래와 동일한 제약을 받습니다.
Q3: deepFreeze는 순환 참조를 어떻게 처리해야 하나요? A3: 순환 참조가 있는 객체는 visited Set(또는 WeakSet)을 사용해 이미 처리한 객체를 건너뛰어야 합니다. 위 예제의 deepFreeze는 이를 반영합니다.
Q4: 프레임워크(예: React)에서 Object.freeze를 사용해도 괜찮나요? A4: 작은 설정이나 읽기 전용 상수에는 괜찮습니다. 하지만 리액트 상태 관리에는 Immer 같은 불변성 라이브러리가 더 적합할 수 있습니다.
정리
- Object.freeze는 얕은 동결로 최상위 속성의 변경을 막는다.
- 중첩 객체의 불변성은 deepFreeze 또는 불변성 라이브러리로 보완해야 한다.
- 성능과 순환 참조를 고려해 적용 범위를 제한하고 체크리스트를 활용하라.
- 실무에서는 설정값 보호, 라이브러리 API 안정성 확보 등에 유용하다.