?. optional chaining
?.
옵셔널 채이닝... 얼마전에 프로젝트를 진행하면서 기존 소스 분석 중에 옵셔널 체이닝을 처음 조우했다.
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 = "멍멍이" <-- 이게 말이 되겠소?
이렇게 된다.
정리,
- obj?.prop - obj가 있다면 prop을 반환, 그렇지 않으면 undefined 반환.
- obj?.[prop] - obj가 있다면 obj[prop] 반환, 그렇지 않으면 undefined 반환
- obj?.method() - obj가 있다면 obj.method() 콜~, 그렇지 않으면 undefined 반환
終