null이나 undefined에 접근하면 에러를 발생한다.
에러가 발생되면 다음 코드가 실행되지 못한다.
에러가 발생될 수 있는 상황을 방지하고 호출되는 값이 거짓인지 의심될 때 옵셔널 체이닝을 사용한다.
📌 false로 인식되는 자료형: ''(빈 문자), 0, false, null, undefined, NaN
?. (Optional chaining)
A ?. B
는 A가 null이나 undefined이면 실행을 멈추고 undefined를 반환한다.
(또는 A가 null/undefined이 아니라 값이 있다면 이어서 B 코드 실행한다.)
옵셔널 체이닝은 연산자가 아니라 함수나 대괄호와 함께 동작하는 특별한 문법 구조체이다.
함수 또는 객체일 때, ?.
형태이다. ex) user?.name
배열일 때, ?.[]
형태이다. ex) user1?.[key]
최신 문법인 옵셔널 체이닝을 사용하기 전에는 논리 연산자를 사용했다.
논리 연산자를 단순히 진리표를 통해 'true/false'로만 알고 있지 말고 A와 B의 관계를 이해하자!
&& (Logical AND)
A && B
는 A가 true이면 B이다. (또는 A가 false이면 false이다.)
|| (Logical OR)
A || B
는 A가 false이면 B이다. (또는 A가 true이면 A이다.)
이 외에 null과 undefined를 걸러내는 연산자가 있다.
?? (Nullish coalescing operator)
A ?? B
는 A가 null이거나 undefined이면 B이다.
(또는 A가 null이나 undefined이 아니면 A이다.)
JavaScript는 숫자 0을 false로 인식한다.
진짜 숫자 0으로 나타내고 싶을 때, 다른 false 값인 null과 undefined만으로 값을 판단해 숫자 0을 false로 인식하지 못하게 한다.
0 ?? ''; // 0
null ?? ''; // ''
✨ 옵셔널 체이닝과 연산자들 각각 어떤 경우에 (뒤의 값)B로 넘어가는지 알고 있기!
함수 자기 자신을 호출하는 함수를 재귀 함수라고 한다.
재귀를 사용할 때 빈번하게 발생하는 문제가 있다.
에러😈 Range Error: Maximum call stack size exceeded
호출 스택의 최대 사이즈를 초과했다는 에러가 발생한다.
이와 같은 현상은 함수 실행이 끝나기 전에 동일한 함수를 계속 호출해서 호출 스택에 함수가 하나씩 하나씩 쌓이게 된다.
결국 호출 스택이 "펑!" 터져버린다.
이 때, 호출 스택과 이벤트 루프 개념을 정확히 알고 있어야 한다!
call stack에만 함수가 쌓여 무리가게 하지 말고, back ground와 task queue에 분배한다.
call stack이 비어지면 이벤트 루프로 함수가 넘어올 수 있게 한다.
해결😝 setTimeout() 메서드로 감싸주기!
'타이머가 0초'라는 것은 함수가 바로 실행되는 것이 아니라 타이머가 background로 넘어가고, 타이머가 0초이기 때문에 background → task queue로 0초만에 바로 넘어간다.
아래와 같은 에러가 발생했을 때, 해결방법은 무엇일까.
에러😈 Uncaught Error: Cannot read property '1' of undefined/null
이 때는 에러가 발생한 코드를 확인해보자.
빨간 줄이 그어진 문제가 있는 코드 '바로 앞' 부분이 undefined 인 것이다.
// '[cellIndex] >= CODE.OPENED' 부분 Error💥 발생
data[rowIndex][cellIndex] >= CODE.OPENED
// 'data[rowIndex]'가 undefined이 발생하는 경우가 있다는 의미
// ?.(옵셔널 체이닝)을 이용해 에러 발생을 방지
data[rowIndex]?.[cellIndex] >= CODE.OPENED
해결😝 ?.
옵셔널 체이닝으로 undefined이나 null이 되는 값을 보호하기!
undefined이나 null에 접근하면 에러가 발생하고 실행 종료하므로 이를 방지하기 위해 옵셔널 체이닝을 사용한다.
✨알아두면 유용할 Tip!👩🏫
① setTimeout() 메서드 사용
비동기로 쉽게 만들 수 있는 코드! 매우 잘 사용되는 코드! 인
setTimeout()으로 약간의 시간을 두고 다른 코드가 먼저 실행될 수 있도록 한다.
마지막 click Event로 인해 화면에 표시되기 전에 상황 종료되어 alert창이 뜰 때, alert가 나중에 실행되도록 해야한다.
화면도 동기적으로 그려지기 때문에 alert를 setTimeout 메서드를 이용해 비동기 코드로 만들면 된다.
setTimeout(() => {
alert(`당신의 승리! ${time}초가 걸렸습니다.`);
}, 500);
// 타이머를 0초로 설정하는 경우가 많음
// 이 경우에는 0초로 설정했을 때 나중에 실행되지 않아서 0초 이상의 시간을 타이머로 설정
② setInterval()과 clearInterval()
setInterval()을 이용해 타이머를 사용하면 clearInterval()으로 타이머를 제거해주자.
const interval = setInterval(() => { // 타이머 설정
const time = Math.floor((new Date() - startTime) / 1000);
}, 1000);
clearInterval(interval); // 타이머 삭제
③ preventDefault()
form에 addEventListener를 적용하면 항상 preventDefault()를 하자.
form을 click 또는 submit하면 기본 동작으로 '새로고침'이 발생한다.
이벤트가 발생할 때마다 새로고침으로 사용자의 입력 값이 리셋되지 않고, 변수에 저장하기 위해 기본 동작을 막는다.
④ 개발 편의를 위한 주석 처리 또는 플래그 변수
게임 개발 시, 개발자 모드와 유저 모드를 구분하기 위해 게임 유저들에게 화면에 보이지 않도록 숨겨야하는 코드는 주석 처리한다.
실무에서 사용되는 방법은 플래그 변수를 만들고 논리 연산자를 이용해 true/false 값에 따라 화면에 표시되는 결과가 달라진다.
const dev = true; // 개발 모드
dev && td.textContent = 'X'; // dev가 true이므로 td에 X 출력
const dev = false; // 유저 모드
dev && td.textContent = 'X'; // dev가 false이므로 코드 실행 불가