본문 바로가기
자바스크립트(JavaScript)/자바스크립트

[JavaScript] 옵셔널 체이닝 " ?. "

by yerica 2024. 12. 26.

옵셔널 체이닝(optional chaning)이란?

옵셔널 체이닝은 ES2020(ECMAScript 2020)에서 정의된 표준 연산자이다.

다른 연사자( +, - , *, /, .등)처럼 값을 평가하는 역할을 하는데, 옵셔널 체이닝은 객체나 속성에 접근할때 동작한다.

옵셔널 체이닝을 사용하면 프로퍼티가 없는 중첩 객체를 에러 없이 안전하게 접근할 수 있다.

옵셔널 체이닝 연산자(?.)는 체인의 각 참조가 유효한지 명시적으로 검증하지 않고,

연결된 객체 체인 내에 깊숙히 위치한 속성 값을 읽을 수 있다.

?. 연산자는 . 체이닝 연산자와 유사하게 작동하지만 만약 참조가 nullish(null 혹은 undefined)라면 에러가 발생하는 대신 표현식의 리턴값을 undefined로 리턴한다. 

따라서 참조가 누락될 가능성이 있는 경우, 연결된 속성으로 접근할 때 더 짧게 간단한 표현식이 생성되는 것이다.

 

간단히 말하자면 ?. 앞의 평가 대상이 undefined나 null이면 평가를 멈추고 undefined를 반환한다.
obj?.prop; // 객체 프로퍼티 호출
obj?.[expr]; // 객체 key 호출
arr?.[index]; // 배열 인덱스 호출
func?.(args); // 함수 호출
옵셔널 체이닝은 ES2020에서 추가된 문법으로, 이전엔 이런 문제들을 해결하기 위해 && 연산자를 사용하곤 했다.
경우(2)에서 임시 변수가 실제로 생성되지 않는 다는 점을 제외하고 예시의 세가지 방법 모든 같은 결과를 반환한다.
// 옵셔널 체이닝으로 작성
let nestedProp = obj.first?.second;

// 옵셔널 체이닝으로 작성하지 않았을 경우(1)
let nestedProp = obj.first && obj.first.second;

// 옵셔널 체이닝으로 작성하지 않았을 경우(2)
let temp = obj.first;
let nestedProp = temp === null || temp === undefined ? undefined : temp.second;
옵셔널 체이닝 앞에 변수는 반드시 선언되어 있어야한다.
변수가 비어있는것은 괜찮지만 아예 선언이 되어있지 않다면 ReferenceError가 발생한다.
// ReferenceError: user is not defined
user?.address;

 

옵셔널 체이닝이 필요한 이유

만약 여러개의 경우의 수 중에서 빈값이 존재할 경우, 원치 않는 에러가 발생할 수 있다.
let user = {}; // 주소 정보가 없는 사용자

alert( user.address.street ); // TypeError: Cannot read property 'street' of undefined
alert( user && user.address && user.address.street ); // undefined, 에러가 발생하지 않는다.
alert( user?.address ); // undefined
alert( user?.address.street ); // undefined

 


위의 예시처럼, user가 null일 때, 바로 alert창으로 띄우면 TypeError가 발생한다.
하지만 && 연산자나 ?. 연산자를 사용하면 undefined라는 값이 리턴되기 때문에 에러가 발생하지 않는다.

 

delete와 조합해 다음과 같이 사용할 수도 있다.
delete user?.name; // user가 존재하면 user.name을 삭제

 

널 병합 연산자(Nullish coalescing operaor)와 같이 사용할 수 있다.

옵셔널 체이닝은 할당자 왼쪽에서 사용불가능.

위의 내용처럼 옵셔널 체이닝은 읽기나 삭제하기에서는 사용 가능하지만 쓰기에서는 사용할 수 있다.

할당자 왼쪽에서 유효하지 않다는 말이다.

// 예시(1)
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment

// 예시(2)
user?.name = "Violet"; // SyntaxError: Invalid left-hand side in assignment
// 에러가 발생하는 이유는 undefined = "Violet"이 되기 때문

 

옵셔널 체이닝은 연산자가 아니다? NO!

옵셔널 체이닝 ?. 는 자바스크립트에서 명확히 연산자로 분류된다.

값을 평가하고 반환하며, 기존 연산자처럼 동작하고 조건부 평가를 수행하며 값이 null또는 undefined일 경우 이후의 평가를 건너뛴다는 점이 옵셔널 체이닝을 연산자로 분류하도록한다.

연산자로 분류되는 이유

1. 값을 평가하고 반환
: 옵셔널 체이닝은 객체의 속성, 배열의 요소, 함수 호출 등을 안전하게 평가하여 결과를 반환한다.
const obj = { a: { b: 2 } };
console.log(obj?.a?.b); // 2
console.log(obj?.c?.d); // undefined​

2. 기존 연산자처럼 동작
: 옵셔널 체이닝은 점(.) 대괄호[ ] 또는 함수호출() 연산자와 결합하여 동작한다.

3. 값 평가를 중단(short-circuit)
: 중단점이라는 특별한 동작을 수행하여 왼쪽 평가 대상에 값이 없으면(null 혹은 undefined) 이후의 평가를 건너뛴다.

 

그런데 왜 연산자가 아니다 라는 말이 나오는 것일까?

이유는 그 동작이 단순히 값을 계산하는 일반적인 연산자와는 조금 다르기 때문이다.

?.는 함수나 대괄호와 함께 동작하는 "특별한 문법구조체(syntax construct)"인데, 기존의 연산자와는 다른 기능을 가지고 있기 때문이다.

특별하다고 여겨지는 이유

1. 안전한 속성 접근
: 기존의 점(.) 연산자는 중단점 없이 무조건 값을 평가하려고 시도한다. 하지만 옵셔널 체이닝은 평가 대상이 nullish할 때 에러를 발생시키지 않고 평가를 중단한다.
이와 같이 조건부로 동작하며 안전성을 강화한 새로운 메커니즘을 제공하기 때문에 특별하다고 느껴진다.

2. 체이닝 지원
: 여러 단계의 중첩된 속성을 한 번에 안전하게 접근할 수 있다.
const obj = { a: { b: { c: 3 } } };
console.log(obj?.a?.b?.c); // 3
console.log(obj?.x?.y?.z); // undefined​

3. 조합 가능
: 옵셔널 체이닝은 배열, 함수 호출 등 다양한 상황에서 조합해서 사용될 수 있다.

 

참고)
1) 모던 javascript 튜토리얼  
2) mdn