[Javascript] Destructuring
JS Destructuring, 구조 분해 할당, JavaScript destructuring
정의
Destructuring 은 배열 또는 객체의 일부를 변수로 풀어내는 ES6 문법. 코드를 짧고 명시적으로.
객체
const { name, age } = user;
const { name: userName } = user; // rename
const { name = 'Anonymous' } = user; // default
const { name, ...rest } = user; // rest
// nested
const { address: { city, zip } } = user;
배열
const [a, b, c] = [1, 2, 3];
const [a, , c] = [1, 2, 3]; // 중간 skip
const [a, b = 10] = [1]; // default
const [head, ...tail] = [1, 2, 3]; // rest, head=1 tail=[2,3]
// swap
let x = 1, y = 2;
[x, y] = [y, x]; // x=2, y=1
함수 매개변수
function greet({ name, age = 18 }) {
return `${name}, ${age}`;
}
greet({ name: 'Alice', age: 30 });
greet({ name: 'Bob' }); // age=18 default
// 배열 인자
function point([x, y]) {
return x + y;
}
point([3, 4]); // 7
자주 쓰는 idiom
API 응답 분해
const { data: { users, total }, error } = response;
React props
function Card({ title, body, onClick }) {
return <div onClick={onClick}>{title}: {body}</div>;
}
옵션 객체
function createUser({ name, role = 'user', verified = false } = {}) {
return { name, role, verified };
}
createUser(); // {} default 까지 적용
createUser({ name: 'A', role: 'admin' });
= {} 가 없으면 createUser() 호출 시 destructure 실패 (TypeError).
map 콜백
users.map(({ name, age }) => `${name} (${age})`);
return 여러 값
function divmod(a, b) {
return [Math.floor(a / b), a % b];
}
const [quotient, remainder] = divmod(10, 3);
// 객체로
function divmod2(a, b) {
return { q: Math.floor(a / b), r: a % b };
}
const { q, r } = divmod2(10, 3);
동적 키
const key = 'name';
const { [key]: value } = user; // user[key] → value
정렬과 결합
const [first, ...rest] = sorted;
const { id, ...others } = obj;
return { ...defaults, ...overrides };
함정
1. default 의 정확한 동작
const { a = 1 } = { a: undefined }; // a = 1 (undefined 만 default 적용)
const { a = 1 } = { a: null }; // a = null (null 은 default 무시)
const { a = 1 } = { a: 0 }; // a = 0
2. nested 의 함정
const { a: { b } } = obj;
// obj.a 가 undefined 면 → TypeError
// 안전한 패턴
const { a: { b } = {} } = obj;
// obj.a 가 undefined 면 {} 로 default
3. 배열의 rest 위치
const [a, ...rest, b] = arr; // ❌ rest 는 마지막만
const [first, ...rest] = arr; // ✓
4. 변수명 vs property 명
const { name } = user; // name 변수에 user.name
const { name: alias } = user; // alias 변수에 user.name
// 헷갈리지 말 것: 콜론의 의미가 객체 리터럴과 반대
const obj = { name: 'value' }; // name 이 키, 'value' 가 값
const { name: alias } = obj; // name 이 키, alias 가 변수
5. 함수 매개변수의 = {}
function fn({ a, b }) { ... }
fn(); // ❌ TypeError (undefined 를 destructure)
function fn({ a, b } = {}) { ... }
fn(); // ✓
모범 사례
- 함수 매개변수 에 적극 사용 (가독성)
- default value +
= {}함께 (안전한 함수) - nested 보다 평탄 (1-2 단계까지)
- swap idiom :
[a, b] = [b, a]
구조 분해 흐름 시각화
flowchart LR
Source["원본 객체 / 배열"] --> Engine["JS 엔진: 프로퍼티 읽기"]
Engine -->|"값 있음"| Var["변수 바인딩"]
Engine -->|"undefined"| Default["default 값 적용"]
Default --> Var
Engine -->|"나머지 항목"| Rest["rest 바인딩"]
TypeScript 와 구조 분해
interface User {
name: string;
age?: number;
address: { city: string; zip: string };
}
// 타입 자동 추론
const { name, age = 18 }: User = user;
// nested 타입 보존
const { address: { city, zip } }: User = user;
// rename 시 타입 유지
const { name: userName }: User = user;
// userName 은 string 타입
// 제네릭 함수에서
function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> {
return Object.fromEntries(keys.map(k => [k, obj[k]])) as Pick<T, K>;
}
// 함수 매개변수 타입 명시
function greet({ name, age = 18 }: { name: string; age?: number }) {
return `${name}, ${age}`;
}
TIP
TypeScript 에서 rename ({ name: alias }) 시 타입은 원본 프로퍼티를 따라간다. alias 는 name 의 타입 그대로.
Map / Set / Iterator 구조 분해
// Map - [key, value] 쌍으로 iterate
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
console.log(key, value); // 'a' 1, 'b' 2
}
const [[firstKey, firstVal]] = map; // firstKey='a', firstVal=1
// Set - 인덱스 없이 값만
const [first, second] = new Set([10, 20, 30]); // first=10, second=20
// 문자열 - utf-16 code unit 단위
const [c1, c2, ...rest] = 'hello';
// c1='h', c2='e', rest=['l','l','o']
// Object.entries / Object.keys / Object.values
const obj = { x: 1, y: 2, z: 3 };
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
// 커스텀 이터레이터
function* range(start, end) {
for (let i = start; i < end; i++) yield i;
}
const [a, b, c] = range(5, 10); // a=5, b=6, c=7
자주 쓰는 라이브러리 패턴
React
// useState / useReducer
const [count, setCount] = useState(0);
const [state, dispatch] = useReducer(reducer, initialState);
// context
const { user, login, logout } = useContext(AuthContext);
// custom hook
function useUser() {
const { data, error, isLoading } = useSWR('/api/user');
return { user: data, error, isLoading };
}
const { user, isLoading } = useUser();
Express / Next.js
// Express route
app.get('/users/:id', ({ params, query, body }, res) => {
const { id } = params;
const { page = '1', limit = '20' } = query;
res.json({ id, page, limit });
});
// Next.js API route
export default function handler({ method, body, query }, res) {
if (method === 'GET') {
const { id } = query;
return res.json({ id });
}
}
비동기 패턴
// Promise.allSettled 결과 분해
const results = await Promise.allSettled([p1, p2, p3]);
for (const { status, value, reason } of results) {
if (status === 'fulfilled') console.log(value);
else console.error(reason);
}
// fetch 응답 분해
const { ok, status, headers } = await fetch('/api/data');
const { data, error } = await res.json();
성능 고려사항
// rest 는 얕은 복사 = 새 객체 생성
const { id, ...rest } = bigObject; // rest 는 새 객체 (메모리 할당)
// 필요한 필드만 추출 (권장)
const { id, name } = bigObject;
// 핫 루프 안 destructuring: V8 이 최적화하므로 걱정 불필요
for (const { name, score } of millionItems) { /* ... */ }
- rest operator 는 얕은 복사. 중첩 객체는 참조 공유.
- 중첩 2단계 이하 권장. 그 이상은 별도 변수로 분리.
{ ...defaults, ...overrides }패턴: 매번 새 객체 생성, GC 부담 가능.
참고
이 글의 용어 (4개)
- [Javascript] Arrayjavascript
- 정의 JavaScript 의 는 순서 있는 객체. 정수 키 + . 풍부한 메서드 (map/filter/reduce/...) 가 함수형 스타일을 지원. 생성 핵심 메서드 (반복) …
- [Javascript] Objectjavascript
- 정의 JavaScript 의 는 key-value 쌍의 컬렉션. 거의 모든 non-primitive 값이 객체. 함수, 배열, 정규식도 객체. 생성 접근 수정 / 삭제 Objec…
- [Javascript] Optional Chaining / Nullish Coalescingjavascript
- 정의 ES2020 도입의 두 가지 단축 문법. - (Optional Chaining) : 중간이 null/undefined 면 반환 - (Nullish Coalescing) : …
- [Javascript] Spread / Restjavascript
- 정의 같은 문법 가 두 가지 의미. - Spread : iterable 을 펼침 (right-hand) - Rest : 나머지를 모음 (left-hand 또는 함수 매개변수) S…
💬 댓글