옵셔널 체이닝 — ?. 연산자로 안전하게 접근
이 토픽을 마치면
?. 연산자가 왜 필요하고 어떻게 동작하는지, 그리고 실무에서 어떤 상황에 쓰는지 알게 됩니다.
중첩 객체의 함정
API에서 받아온 사용자 데이터가 있습니다:
const user = {
name: "Alice",
address: {
city: "Seoul"
}
};
console.log(user.address.city); // "Seoul"그런데 어떤 사용자는 주소를 입력하지 않았습니다:
const user = { name: "Bob" };
console.log(user.address.city);
// TypeError: Cannot read properties of undefineduser.address가 undefined인데, 거기서 .city를 읽으려니 에러가 납니다. JavaScript에서 가장 흔한 런타임 에러입니다.
예전 방식: if문의 연쇄
let city;
if (user && user.address && user.address.city) {
city = user.address.city;
}매번 중간 단계를 확인해야 합니다. 깊이가 깊어질수록 코드가 길어집니다.
옵셔널 체이닝: ?.
const city = user?.address?.city;?.는 왼쪽 값이 null이나 undefined이면 에러를 내지 않고 undefined를 반환합니다.
user?.address?.city는 이렇게 읽습니다:
user가 있으면.address로 진행address가 있으면.city로 진행- 어디서든
null이나undefined를 만나면 즉시undefined반환
한 줄로 안전한 접근이 가능합니다.
메서드와 배열에도 적용
메서드 호출에도 쓸 수 있습니다:
const result = user.getProfile?.();getProfile이 존재하면 호출하고, 없으면 undefined를 반환합니다. 괄호 앞에 ?.를 붙입니다.
배열 인덱스 접근에도 됩니다:
const first = users?.[0]?.name;users 배열이 없거나 빈 배열이어도 에러가 나지 않습니다.
nullish 병합(??)과 조합
?.와 자주 함께 쓰이는 게 **nullish 병합 연산자 ??**입니다:
const city = user?.address?.city ?? "Unknown";?.로 안전하게 접근하고, 결과가 null이나 undefined이면 ?? 뒤의 기본값을 씁니다. ||와 다르게 0이나 ""(빈 문자열)은 유효한 값으로 취급합니다.
const count = data?.total ?? 0; // total이 0이면 0을 유지
const count2 = data?.total || 0; // total이 0이면 0도 falsy라 0을 반환 (의도와 다를 수 있음)과도한 사용 주의
?.가 편하다고 모든 곳에 붙이면 안 됩니다:
// 이건 과도합니다
const name = user?.name?.toString?.()?.trim?.();user.name이 반드시 있어야 하는 상황이라면 ?. 없이 접근하는 게 맞습니다. 에러가 나야 버그를 잡을 수 있습니다.
?.는 "이 값이 없을 수도 있다"는 의미를 코드에 전달합니다. 진짜 없을 수 있는 곳에만 쓰세요.
핵심
?.는null/undefined를 만나면 에러 대신undefined를 반환합니다. API 응답처럼 구조가 불확실한 데이터에 접근할 때 사용합니다.??와 조합하면 기본값까지 깔끔하게 처리할 수 있습니다.