자바스크립트에 Optional Chaining을 사용하면 함수나 객체의 속성을 호출할 때 호출하는 값이 정의되지 않았거나 falsy 한 값인 경우 오류를 발생시키는 대신 undefined를 반환하게 해 주어 예상치 못한 런타임 에러를 막아준다.
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// Expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// Expected output: undefined
위 예시처럼 실제 존재하지 않는 객체의 dog를 호출하거나 함수를 호출해도 Optional Chaining 덕분에 에러가 발생하지 않고 undefined를 반환하고 있음을 확인할 수 있다. 만약 Optional Chaining을 사용하지 않았더라면 밑에 예시처럼 될 것이다.
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const peopleName = adventurer.people.name;
console.log(peopleName);
// Error: Cannot read properties of undefined (reading 'name')
const dogName = adventurer.dog?.name;
console.log(dogName);
console.log(adventurer.someNonExistentMethod?.());
peopleName을 호출하자마자 밑에 코드들은 실행도 되기 전에
이렇듯 굉장히 유용하게 사용할 수 있는 Optional Chaining은 기존 코드를 리팩터링 할 때 주의할 점이 존재한다.
vscode 리팩터링 기능이나 여러 글들을 보면 a && a.b 이런 코드들을 a?.b로 바꾸는 경우를 많이 봤을 텐데 첫 번째로 그렇게 바꿨을 경우 값이 다른 경우들을 보여주겠다.
function test(value) {
console.log(`${value && value.length}, ${value?.length}`);
}
test(undefined); // undefined, undefined
test(null); // null, undefined
test(true); // undefined, undefined
test(false); // false, undefined
test(1); // undefined, undefined
test(0); // 0, undefined
test({}); // undefined, undefined
test([]); // 0, 0
test({ length: "a" }); // a, a
test(''); // , 0
test(NaN); // NaN, undefined
주석의 값으로 보듯이 항상 같은 결과를 뱉고 있지 않다는 점에 유의하자
두 번째로 빈 문자열은 falsy 하지만 nullish 하지 않는 값이므로 사용했을 시 문제가 발생한다.
function tt(s) {
// without optional chaining
if (s && s.length === 0) {
// not called for the empty string
console.log(1);
}
// with optional chaining
if (s?.length === 0) {
// called for the empty string
console.log(2);
}
}
tt('');
// Expected output: 2
빈 문자열을 사용하여 함수 호출 시 Optional Chaining코드 조건문은 통과하는 것에 유의하자
세 번째로 Optional Chaining코드는 null 대한 결과를 undefined로 바꾼다. 그러나 기존 && 코드 사용 시 null을 반환한다.
null && null.status;
// Expected output:null
null?.status
// undefined
const testObject = undefined;
// testObject가 존재 할 때만 status값을 확인하는 조건문을 쓰고자 할 시 아래와 같은 문제가 발생
// 의도한데로 testObject 값이 null이든 undefined이든 falsy한 값이면 조건문을 통과하지 못한다.
if (testObject && testObject.status !== "testStatus") {
console.log("테스트1");
}
// 옵셔널체이닝 사용시 값을 undefined로 바꿔버리기에 비교를 하면 undefined랑 비교를 하는 게 아닌 이상 무조건 다르다
if(testObject?.status !== "testStatus") {
console.log("테스트2");
}
// Expected output: 테스트2
네 번째로 부작용이 있는 호출에 사용 시 문제가 발생할 수 있습니다. 혹시 부작용을 나쁜 작용으로 생각하시는 분들이 계시다면 부작용에 대해 검색해 한 번 뜻에 대해 이해하시는 걸 추천드립니다!!
f() && f().a
↓
f()?.a
// f는 기존 두 번 호출되지만 옵셔널체이닝 사용 시 한 번으로 호출 횟수가 줄기에 만약에 f에 부작용이 존재하고
// 이를 감안해서 사용하고 있을 시 문제가 발생할 수 있습니다.
다섯 번째로 TypeScript에서는 void 형식의 Optional Chaining을 지원하지 않는다.
type Input = void | {
property: string
};
function f(input: Input) {
// this works:
console.log(input && input.property);
// this breaks because void is not undefined in TypeScript:
console.log(input?.property);
}
마지막으로 Optional Chaining은 ES2020 기능이므로 모든 최신 브라우저 및 Node 14+에서 지원되지만 이전 브라우저 및 Node 버전의 경우 변환이 필요할 수 있다고 한다.
'개발 > JavaScript' 카테고리의 다른 글
[JavaScript] await? return await? return? (0) | 2023.03.25 |
---|---|
[TypeScript] 타입 공간과 값 공간의 심벌 구분하기! (0) | 2023.02.26 |
[JavaScript] call by value, call by reference, call by sharing (0) | 2023.02.07 |
[JavaScript] 인자 개수가 자유로운 함수 선언(arguments) (0) | 2023.02.05 |
[JavaScript] parameter vs argument (0) | 2023.02.04 |
댓글