본문 바로가기
Dev/javascript

?. optional chaining

by 괴발짜응 2022. 11. 7.
반응형

?.

옵셔널 채이닝... 얼마전에 프로젝트를 진행하면서 기존 소스 분석 중에 옵셔널 체이닝을 처음 조우했다.

summary.certification = d1?.analysis?.static?.certification?.valid;

요런 식인데... 그래도 이 바닥에서 대략 20년이 넘게 굴렀다고, 대략 "음... 삼항연산 하듯이 해서 객체 체인의 참조가 유효한지에 대해 판단하는건가보구만..."  정도로 생각하고 있었더랬다... 얼추 비슷하다

 

그러다가 json 핸들링 할 일이 많은 프로젝트를 진행 중이었는데... 저 옵셔널 채이닝을 사용하지 않다보니... 

개발부 본부장이 "js 전문이라면서 어떻게 이런 것도 모르냐"며 꼽을 주더라고... 하~ XX 할많하않~

 

사실 ECMA는 19년도까지만 보고 이 후에는 잘 찾아보질 않았다. 굳이 그럴 필요가 없었으니까... 그러다보니 ECMA2020에서 추가 된 옵셔널 채이닝을 내가 알 턱이 없지... 학습이 부족했던게 맞긴하지만, 그렇다고 이렇게 꼽을 먹어야 되나하는 생각이 들더라고... 아니 뭐 지는 Modern C++ 다 꿰차고 있나... 

 

아무튼 그래서 말 나온 김에 "옵셔널 채이닝"을 정리해 보려고 한다.

 

Optional Chaining이 대체 무엇이냐...

optional chaining 연산자 ?. 는 체인의 각 참조가 유효한지 명시적으로 검증하지 않고, 연결된 객체 체인 내에 깊숙이 위치한 속성 값을 읽을 수 있다.

 

그러니까, 참조가 null 이거나 undefined 라면, 에러 대신 표현식의 리턴 값은 undefined로 단락된다.

따라서, 참조가 누락될 가능성이 있는 경우 더 짧고 간단한 표현식이 생성된다. 

optional chaining은 선언되지 않은 루트 객체에 사용할 수 없지만, 정의되지 않은 루트 객체와는 함께 사용할 수 있다.

 

아래와 같은 상황에서

let animal = {};
console.log(animal.dog.name); // Uncaught TypeError: Cannot read properties of undefined (reading 'name')

//querySelector(...) 호출 결과가 null 이면 error난다
let html = document.querySelector('.myClass').innerHTML;

?. 연산자가 사용되기 전에는 보통

let animal = {};

console.log(animal && animal.dog && animal.dog.name); //undefined

이와 같이 표현을 했더랬고, 지금도 잘 써 먹고 있습니다. 그런데 ?. 몰랐다고 꼽을... 

그렇다면 이걸 optinal chaining을 사용한다면,

let animal = {};

console.log(animal?.dog?.name); // undefined 에러 없음

이렇게 되겠죠. 

ler animal = null;

console.log(animal?.dog) //undefined
console.log(animal?.dog.name) //undefined

?.은 바로 앞만 평가를 하고 확장은 되지 않습니다. 

위의 예제는 animal이 null 또는 undefined인 경우만 처리할 수 있습니다.  animal이 null 이나 undefined가 아니고 실게 값이 존재하는 경우에는 반드시 animal.dog 프로퍼티는 있어야 한다. 안그러면 animal?.dog.name의 두번째 . 연산자에서 에러가 남

 

주의사항

1. 옵셔널 체이닝을 남용하지 말라.

?.는 존재하지 않아도 괜찮은 대상만으로 하세요. 논리상 animal은 반드시 존재해야 하나 dog는 필수가 아니다. 그러면 animal.dog?.name을 사용하는 것이 맞음

 

2. ?.앞의 변수는 꼭 선언되어야 한다.

// let animal = {};

animal?.dog; // ReferencError: animal is not defiend

단락 평가

?.는 왼쪽 평가대상에 값이 없으면 즉시 평가를 멈춘다.

let animal = null;
lex x = 0;

animal?.countDog(x++); // animal이 null이기 때문에 아무 일도 없다
console.log(x);  // 0, x는 증가하지 않는다.

?.() && ?.[ ]

그렇다면, 이런 경우는 어떨까?

let animal1 = {
	cat () {
    	alert("냐옹~~")
    }
}
let animal2 = {};
console.log(animal1.cat?.()); // 냐옹~~
console.log(animal2.cat?.()); // undefined


let animal3 = {
	dog: {
    	name: "김똥개"
    }
}
let animal4 = null;
let key = "dog";
console.log(animal3?.[key]); // {name: "김똥개"}
console.log(animal4?.[key]); // undefined

delete 와 함께 사용하기 

별거 있나 그냥 지워진다.

delete animal?.dog; // animal이 있으면 dog를 삭제한다

참고사항, .?는 읽기와 삭제는 가능하지만, 할당은 되지 않습니다. 즉,

animal?.dog = "멍멍이"; //SyntaxError: Invalid left-hand side in assignment
// undefined = "멍멍이" <-- 이게 말이 되겠소?

이렇게 된다.

 

정리,

  1.  obj?.prop - obj가 있다면 prop을 반환, 그렇지 않으면 undefined 반환.
  2. obj?.[prop] - obj가 있다면 obj[prop] 반환, 그렇지 않으면 undefined 반환
  3. obj?.method() - obj가 있다면 obj.method() 콜~, 그렇지 않으면 undefined 반환
반응형