킹의 개발일지

Optional Chaining 본문

프로그래밍 언어/Js

Optional Chaining

k1ng 2023. 4. 27. 14:16

Cannot read properties of undefined (reading '...')

mongoose를 사용해서 스키마를 만드는데, 계속해서 Cannot read properties of undefined(reading 'users') 이놈의 에러가 나를 계속 괴롭혔다. 

 

문제의 코드

const Users = models.users || model('users', userSchema);

 

위 코드로 의도한 바는, users 스키마가 정의 돼 있다면(models.users) 그것을 쓰고 아니면 새 스키마를 생성해라는 의도였다. 그런데, 의도와는 다르게 어느 순간부터 Cannot read properties of undefined(reading 'users') 이 에러가 발생하는것이 아닌가..

 

메세지를 곰곰히 생각해보면 'models가 undefined니까 users를 읽을 수 가 없어요!' 하는 말이다. 그럼 'models'가 만약 undefined일 때 model('users' userSchema)를 사용하면 될것 같다. 하지만 models 객체는 내가 원하는 것이 아니다. 나는 models 객체에 있는 users를 원하기 때문에 마냥 models || model('users', userSchema) 만으로는 의도한 결과를 도출 할 수 없다. 그래서 언어 차원에서 지원하는 문법을 찾아보던중 재미난 녀석을 발견했다.

 

Optional Chaining

optional chaining '?.' ?.'앞’의 평가 대상이 undefined null이면 평가를 멈추고 undefined를 반환한다. 그럼 다음과 같이 사용하면, models가 undefined일 때도 터지지 않고 || 문 뒤의 코드로 스키마를 생성해서 사용할 것이다.

models?.users || model('users', userSchema);

 

이렇게 하면 undefined인 객체에 접근하여 생기는 에러를 막을 수 있을 것이다. 

또한 아래와 같은 이유로 큰 서비스의 경우 옵셔널 체이닝을 막 남용하지 않는것이 좋다고도 한다.

nullish 병합 연산자 '??'

옵셔널 체이닝을 공부하던 중 그와 비슷하게 생긴 ?? 연산자를 보았는데, 재밌어서 좀더 다뤄보겠다. 생긴것은 ?. 와 비슷한데, 하는것은 꼭 삼항연산자를 사용하는 것과 비슷하다.

 

문법은 아래와 같다. 그리고 하는 일은 변수가 null 또는 undefined일 때 ?? 뒤에 있는 코드를 실행 시켜주는 일을 한다.

let firstName = null;
let lastName = null;
let nickName = "바이올렛";

// null이나 undefined가 아닌 첫 번째 피연산자
alert(firstName ?? lastName ?? nickName ?? "익명의 사용자"); // 바이올렛

위 코드 결과로 바이올렛이 출력됨을 확인 할 수 있다.

 

이 녀석이 하는 일이 문듯 '||' 연산자와 비슷해보인다. 그러나 조금의 차이가 있으니 이것을 설명해 보겠다.

 

위 코드의 ??를 ||로 바꿔도 바이올렛이 출력될 것이다. 그러나 ||은 0, "", undefinded, false 같은 값을 전부 검사하는데 비해, ?? 연산자는 undefined 하고 null 같은 nullish 만 검사한다는 차이가 있다.


다시 돌아와 나를 괴롭히던 코드를 치료해보자면,

const Users = models?.users ?? model('users', userSchema);

다음과 같이 바꿔주었고 원하던 로직을 유지한 채로 에러를 해결 할 수 있었다! 

 

만약 이런 검사를 if문으로 검사했다면 코드가 상당히 길어졌을 것이다.

 

솔직히 지나가다 몇번씩 본 연산자들 이었지만 직접 사용해보지 않아서 공감을 못했었는데, 실제 이런 문제를 접하니 괜히 언어 차원에서 이런 문법을 지원해주는 것이 아니라는 것을 느낄 수 있었다.

'프로그래밍 언어 > Js' 카테고리의 다른 글

Promise.all, Promise.allSettled  (0) 2023.09.11
JavaScript - async & await  (0) 2023.03.30
JavaScript - Promise (then, catch)  (0) 2023.03.29