본문으로 건너뛰기
김신건의 로그

[Javascript] Optional Chaining / Nullish Coalescing

· 수정 · 📖 약 1분 · 198자/단어 #javascript #optional-chaining #nullish #syntax
JS Optional Chaining, ?., ??, JS Nullish

정의

ES2020 도입의 두 가지 단축 문법.

  • ?. (Optional Chaining) : 중간이 null/undefined 면 undefined 반환
  • ?? (Nullish Coalescing) : 왼쪽이 null/undefined 면 오른쪽 사용

Optional Chaining ?.

user?.address?.city
// user 가 null/undefined 면 즉시 undefined
// 그 외에는 평소처럼 평가

// 옛 방식
user && user.address && user.address.city

메서드 호출

obj.method?.()         // method 가 없으면 undefined, 있으면 호출
arr?.[0]               // 배열 인덱스
fn?.(arg)              // 함수 호출

함수 호출 우회

window.callback?.(data)    // callback 정의되어 있을 때만 호출

Nullish Coalescing ??

const port = config.port ?? 3000;
// port 가 null 또는 undefined 면 3000, 그 외 그대로

|| 과의 차이:

0 || 'default'           // 'default'  (0 은 falsy)
0 ?? 'default'           // 0          (null/undefined 만 default)

'' || 'fallback'         // 'fallback'
'' ?? 'fallback'         // ''

null || 'x'              // 'x'
null ?? 'x'              // 'x'

undefined || 'x'         // 'x'
undefined ?? 'x'         // 'x'

?? 가 더 명확. 0, ”, false 가 유효한 값일 때 ?? 필수.

Nullish Assignment ??=

obj.a ??= 'default';
// obj.a 가 null/undefined 면 'default' 할당
// 동등: obj.a = obj.a ?? 'default';

다른 단축:

  • ||= : falsy 면 할당
  • &&= : truthy 면 할당
config.timeout ||= 5000;     // 0, '', false 도 덮어씀
config.timeout ??= 5000;     // null/undefined 만 덮어씀
config.flag &&= 'enabled';   // truthy 면 'enabled' 로

자주 쓰는 패턴

API 응답 안전 접근

const username = response?.data?.user?.name ?? 'Guest';

옵션 객체 default

function api({ timeout, retries } = {}) {
    timeout = timeout ?? 5000;
    retries = retries ?? 3;
}

콜백 안전 호출

function process(items, { onSuccess, onError } = {}) {
    try {
        const result = doWork(items);
        onSuccess?.(result);
    } catch (e) {
        onError?.(e);
    }
}

배열 / Map 안전 lookup

const first = arr?.[0];
const value = map.get?.(key);    // map 자체가 없을 수도
const found = users?.find?.(u => u.id === id);

React state

const name = user?.profile?.name ?? 'Anonymous';

함정

1. ?? 와 || 의 우선순위

a || b ?? c       // ❌ SyntaxError (괄호 필요)
(a || b) ?? c     // ✓
a || (b ?? c)     // ✓

??|| / && 는 함께 쓸 때 괄호 필수.

2. ?. 의 short-circuit

user?.greet().toUpperCase()
// user 가 undefined 면 → undefined.toUpperCase() ❌ TypeError

user?.greet()?.toUpperCase()
// 안전한 chaining

각 단계마다 ?. 필요.

3. 할당의 왼쪽에는 못 씀

obj?.x = 1    // ❌ SyntaxError
if (obj) obj.x = 1;

4. delete 와의 조합

delete obj?.prop
// obj 가 null 이면 무시, 있으면 delete

이건 가능.

5. 0, false, ” 의 처리

function getCount({ count = 10 } = {}) {
    return count;
}
getCount({ count: 0 });     // 0 (default 적용 안 됨)
getCount({ count: null });   // null (default 적용 안 됨, ⚠️)
getCount({});                 // 10

= default 는 undefined 만 적용. null 처리에 ?? 활용.

function getCount({ count } = {}) {
    return count ?? 10;
}
getCount({ count: null });   // 10 ✓

참고

이 글의 용어 (3개)
[Javascript] 타입 변환 / 강제 변환javascript
정의 JavaScript 의 암묵적 형변환 (coercion). 연산자가 양쪽 피연산자의 타입을 자동으로 맞춘다. 명시적 변환과 구분. 3 가지 강제 변환 1. ToString …
[Javascript] boolean / null / undefinedjavascript
정의 JavaScript 의 3 가지 primitive. - : , - : 의도적인 "없음" - : 자동으로 부여된 "없음" (초기화 안 됨) boolean falsy / tru…
[Javascript] Destructuringjavascript
정의 Destructuring 은 배열 또는 객체의 일부를 변수로 풀어내는 ES6 문법. 코드를 짧고 명시적으로. 객체 배열 함수 매개변수 자주 쓰는 idiom API 응답 분해…

이 개념을 다룬 위키 페이지 (1)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기