🌱 Optional Chaining 이란?
ES2020에서 등장한 새로운 연산자로서 ?.
의 형태로 사용한다.
연산자를 통한 속성값 접근의 문제점으로, 여러 단계로 이루어진 객체(중첩구조)를 탐색할 때는 항상 TypeError가 발생할 확률이 생기기 때문에 이에 대한 대안으로 등장한 연산자이다.
체인으로 이루어진 각 참조가 유효한지 명시적으로 검증하지 않고, 연결된 객체 체인 내에 깊숙히 위치한 속성 값을 읽을 수 있는 연산자이다.
즉, 체이닝 연산자(.
)와 비슷하게 동작하지만, 만약 참조가 null 혹은 undefined여도 에러식을 뱉지 않고 undefined값을 리턴한다.
함수 호출시에도 마찬가지로 값이 없다면 undefined를 리턴한다.
Optional chaining을 사용하므로써 문법의 가독성이 올라가고 간결한 표현식으로 작성할 수 있게 된다.
속성값이 존재한다는 확실한 보증이 없을 경우 그 객체를 탐색하는 데 도움을 준다.
자바스크립트에서는 주로 . 연산자(chaining)를 사용해서 객체의 속성값에 접근한다. 그러나 객체에 접근했을 때 값이 없을 수도 있다(=error).
객체의 속성을 접근할 때, .
연산자 대신에 옵셔널 체이닝(optional chaining, ?.
)을 사용하면, 해당 객체가 nullish (= undefined나 null) 인 경우에 TypeError 대신에 undefined를 얻게되어 프로퍼티가 없는 중첩 객체를 에러 없이 안전하게 접근할 수 있다.
🔆 사용 형태
- 물음표 기호와 온점(
?.
)을 사용.- 참조가 null / undefined 라면, 에러(error) 대신 undefined 리턴.
- 주어진 함수가 없으면 undefined.
- 배열이나 함수에도 사용할 수 있다.
🌱 Optional Chaining 사용 예시
🪴 ?.
?.
로 표현할 수 있다.// 객체 (중첩구조)
const animals = {
cat: { name: "나비" },
lion: { name: "호랑이" }
}
// 중첩구조에서 속성값 읽는 방법 (1) -> 논리연산자 && 활용 (좌항 연산자가 true인 경우에만 우항 연산자를 불러올 수 있다.)
const catName = animals.cat && animals.cat.name;
// 중첩구조에서 속성값 읽는 방법(2) -> optional chaining
const catName = animals.cat?.name;
console.log(catName); // "나비"
const dogName = animals.dog?.name;
console.log(dogName); // undefined -> animals에는 dog속성이 없기때문에 dog?.name 도 undefined이다.
🪴 ?.()
와 ?.[]
?.()
(함수) 와 ?.[]
(배열)로 표현할 수 있다// user1 객체 내부에는 메서드(함수) admin이 있다
let user1 = {
admin() {
alert("관리자 계정입니다.");
}
}
// user2 객체는 메서드가 없다
let user2 = {};
user1.admin?.(); // 관리자 계정입니다.
user2.admin?.(); // undefined
user 객체는 반드시 존재하기 때문에 admin 프로퍼티엔 .
만 사용해 접근했다.
그리고 난 후 ?.()
를 사용해 admin 메서드의 존재 여부를 확인했다.
user1엔 admin이 정의되어 있기 때문에 메서드가 제대로 호출되는 반면,
user2엔 admin이 정의되어 있지 않기에 에러 없이 그냥 평가가 멈추는 것을 확인 할 수 있다.
let user1 = {
firstName: "Violet"
};
let user2 = null; // user2는 권한이 없는 사용자라고 가정.
let key = "firstName";
alert( user1?.[key] ); // Violet
alert( user2?.[key] ); // undefined
alert( user1?.[key]?.something?.not?.existing); // undefined
.
대신 대괄호([]
)를 사용해 객체 프로퍼티 키(key)에 접근하는 경우엔 ?.[]
를 사용할 수 있다.
❗️객체의 속성(property)에 접근하는 방법에는 2가지가 있다.
1) 점 표기법 : 마침표(.
)를 사용하여 객체의 속성값에 접근
2) 대괄호 표기법 : 대괄호([ ]
)를 사용하여 객체의 속성값에 접근let obj = { one : 1, two : 2, } console.log(obj["one"] + "vs" + obj.two) // 1 vs 2
위 예시처럼 2가지 접근법이 모두 사용 가능하다.
단, 점 접근법을 사용할 수 없는 경우도 존재한다. 프로퍼티 키(key) 이름이 유효한 자바스크립트 이름이 아니거나, 숫자로 이루어져있거나, 예약어 인 경우, 프로퍼티 값은 대괄호 표기법으로 읽어야 한다.
대괄호 표기법을 사용하는 경우, 대괄호 내에 들어가는 프로퍼티 이름은 반드시 문자열이어야 한다.let person = { 'first-name': 'devvv', 'last-name': 'Lee', gender: 'male', 1: 10 }; console.log(person.first-name); // NaN: undefined-undefined console.log(person[first-name]); // ReferenceError: first is not defined console.log(person['first-name']); // 'devvv' console.log(person.gender); // 'male' console.log(person[gender]); // ReferenceError: gender is not defined console.log(person['gender']); // 'male' console.log(person['1']); // 10 console.log(person[1]); // 10 : person[1] -> person['1'] console.log(person.1); // SyntaxError
❗️ 옵셔널 체이닝을 남용하지 말자
?.
은 존재하지 않아도 괜찮은 대상(필수값이 아닌 대상)에서만 사용해야 한다.let user = null; // user 정보가 없다 alert( user?.address ); // undefined // user?. 평가가 끝나고 user에 값이 없다는 것이 판별되면, 그 즉시 평가를 멈추기 때문에 아래 두 줄에서 에러가 발생하지 않는다. // 즉, 평가가 끝나면 나머자 프로퍼티들엔 접근 자체를 하지 않기 때문이다. alert( user.address?.street ); // undefined alert( user.address?.street.anything ); // undefined // 다만 user가 존재하는 경우엔 user.address 같은 중간 프로퍼티들이 평가대상이 되기 때문에 반드시 값이 있어야 에러가 발생하지 않는다.
위 예시에서 논리상 user는 반드시 있어야 하는데, address는 필수값이 아니다.
그러니user.address?.street
를 사용하는 것이 바람직하다.