ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • IIFE + 구조분해로 객체 키 제거하기
    JavaScript 2026. 6. 26. 22:42

    "라이브러리 없이, 한 줄로, 불변하게"

     

    들어가며

    특정 키를 제외한 나머지 객체를 만들고 싶을 때 어떻게 하시나요?


    delete를 쓰자니 원본을 뮤테이트하고, lodash.omit을 쓰자니 의존성이 생깁니다.

     

    이 글에서는 IIFE(즉시 실행 함수 표현식)Rest 구조분해 를 조합해서 외부 라이브러리 없이 깔끔하게 키를 제거하는 패턴을 소개합니다 💘

     

    핵심 패턴

    const result = (({ password, __v, ...rest }) => rest)(user);

    딱 한 줄입니다. 분해해서 보면,

    const result = (
      ({ password, __v, ...rest }) => rest  // 1. 화살표 함수: 제거할 키를 명시적으로 구조분해
    )(user);                                 // 2. 즉시 호출
    • password, __v — 제거하고 싶은 키
    • ...rest — 나머지 프로퍼티를 모아 새 객체 생성
    • IIFE로 감싸 임시 변수 없이 즉시 실행

     

    왜 이렇게 하나요 🤔

    delete 방식의 문제점

    const copy = { ...user };
    delete copy.password;

    직관적이지만 두 줄이 필요하고, 실수로 delete user.password처럼 원본을 건드릴 위험이 있습니다.

     

    평범한 구조분해의 불편함

    const { password, __v, ...rest } = user;
    // 이제 `password`와 `__v`가 스코프에 남아있음

    제거하려고 분해했는데 오히려 변수가 생겨 스코프가 오염됩니다.

    린터가 *"declared but never used"* 를 경고하기도 합니다.

    IIFE 패턴의 장점

    const result = (({ password, __v, ...rest }) => rest)(user);
    항목 평가
    원본 불변 ✅ 새 객체 반환
    스코프 오염 ✅ 없음
    외부 의존성 ✅ 없음
    가독성 ⚠️ 익숙해지면 OK
    제거할 키 명시 ✅ 한눈에 보임

    ~실전 예시~

    😝 API 응답에서 민감 정보 제거

    async function getPublicUser(id) {
      const user = await db.findUser(id);
    
      return (({ password, salt, refreshToken, ...rest }) => rest)(user);
    }

    🐶 React에서 컴포넌트에 props 전달 시 필터링

    function Button({ onClick, children, analyticsId, ...rest }) {
      // analyticsId는 DOM에 전달하면 경고 발생 → 제거 필요
      return <button onClick={onClick} {...rest}>{children}</button>;
    }

    여기서는 구조분해 자체가 필터링 역할을 하므로 IIFE 없이 더 자연스럽습니다.


    IIFE 패턴이 특히 빛나는 경우는 이미 완성된 객체에서 키를 빼야 할 때입니다.

    const payload = (({ _id, createdAt, ...rest }) => rest)(formData);
    await api.post('/submit', payload);

    여러 키를 동적으로 제거하고 싶다면?

    이 패턴의 한계입니다. 제거할 키가 런타임에 결정된다면 다른 방식이 필요합니다

    // 동적 키 제거는 reduce가 더 적합
    const omit = (obj, keys) =>
      Object.fromEntries(
        Object.entries(obj).filter(([k]) => !keys.includes(k))
      );
    
    const result = omit(user, ['password', '__v']);

     

    이 패턴, 흔히 쓰이나요?

    솔직히 말하면 — 적당히 쓰입니다.

    코드베이스에서 마주치면 "아는 사람 코드"라는 느낌이 드는 패턴입니다.

    쓰이는 상황

    • 백엔드(Node.js) 에서 API 응답 객체를 정제할 때 종종 등장
    • 유틸 함수 없이 빠르게 한 줄로 처리하고 싶을 때
    • TypeScript 프로젝트에서 타입 안전하게 Omit<T, K>와 함께 쓸 때
    function omitKey<T, K extends keyof T>(obj: T, ...keys: K[]): Omit<T, K> {
      return (({ ...rest }) => {
        keys.forEach(k => delete (rest as T)[k]);
        return rest;
      })(obj) as Omit<T, K>;
    }

    쓰이지 않는 상황

    • 팀 코드베이스에서는 lodash/omit 또는 별도 유틸 함수로 추상화하는 경우가 더 많음
    • 주니어가 많은 팀에서는 가독성 이슈로 리뷰에서 걸리기도 함
    • 제거할 키가 3개 이상이면 한 줄이 너무 길어짐

     

    결론 >>> 혼자 쓰거나 소규모 프로젝트에서는 충분히 가치 있는 패턴입니다.
    다만 팀에서 쓰려면 유틸 함수로 감싸거나, 최소한 주석 한 줄은 달아주세요.
    영리함이 가독성을 이기면 기술 부채가 됩니다.

     

    요약....

    IIFE + Rest 구조분해 조합은 JavaScript의 여러 기능이 맞물려 만들어진 작은 숙어(idiom)입니다. 알고 나면 의존성 없이 한 줄로 처리할 수 있어 유용하지만, 팀 컨텍스트를 고려해 적용 여부를 하자.

     

    제거할 키가 정적이고 소수일 때 → 이 패턴
    제거할 키가 동적이거나 다수일 때 → Object.fromEntries + filter 또는 lodash/omit

Designed by Tistory.