[Javascript] nullish 병합 연산자 (nullish coalescing operator)
nullish
nullish 병합 연산자 (nullish coalescing operator) ?? 를 사용하면 짧은 문법으로 여러 피연산자 중 그 값이 '확정되어 있는' 변수를 찾을 수 있다.
a ?? b 의 평가 결과는 아래와 같다.
- a가 null도 아니고 undefined도 아니면 a
- 그 외의 경우에는 b
nullish 병합 연산자 ?? 없이 x = a ?? b 와 동일한 동작을 하는 코드는 다음과 같다.
x = (a !== null && a !== undefined) ? a : b;
아래의 예시를 살펴보자.
let firstName = null
let lastName = undefined
let nickName = 'zubetcha'
console.log(firstName ?? lastName ?? nickName ?? 'anonymous') // 'zubetcha'
console.log(lastName ?? firstName ?? 'anonymous' ?? nickName) // 'anonymous'
첫 번째 console.log
- firstName의 값은 null 이기 때문에 무시하고 그 다음에 있는 피연산자인 lastName의 값을 평가한다.
- lastName의 값은 undefined 이기 때문에 무시하고 그 다음에 있는 피연산자인 nickName의 값을 평가한다.
- nickName의 값은 'zubetcha' 이기 때문에 (null 이나 undefined이 아니기 때문에) 해당 값을 반환하고 그 다음에 있는 피연산자인 'anonymous' 는 평가하지 않는다.
두 번째 console.log
- lastName의 값은 undefined 이기 때문에 무시하고 그 다음에 있는 피연산자인 firstName의 값을 평가한다.
- firstName의 값은 null 이기 때문에 무시하고 그 다음에 있는 피연산자인 'anonymous' 를 평가한다.
- 'anonymouse' 는 String 으로, null 이나 undefined가 아니기 때문에 nullish 병합 연산자는 'anonymous' 를 반환하고 그 다음에 있는 피연산자인 nickName은 평가하지 않는다.
하지만 위와 같은 연산은 || 을 통해서도 동일한 값을 얻을 수 있다. 아래와 같이 ?? 를 || 로 변경하여도 동일하게 'zubetcha'와 'anonymous'가 출력되는 것을 확인할 수 있다. 그렇다면 ?? 와 || 에는 어떤 차이가 있을까?
console.log(firstName || lastName || nickName || 'anonymous') // 'zubetcha'
console.log(lastName || firstName || 'anonymous' || nickName) // 'anonymous'
|| 와의 차이
- || 는 첫 번째 truthy 값을 반환한다.
- ?? 는 첫 번째 정의된(defined) 값을 반환한다.
?? 와 || 의 차이는 숫자 0 등과 같이 false 로 간주하는 값을 어떻게 인식하여 처리하는지에 있다. || 는 숫자 0을 falsy한 값으로 취급하여 null 이나 undefined를 할당한 것과 동일하게 처리하지만, ?? 는 반드시 정확하게 null 이나 undefined를 가지고 있는 게 아니면 본래 할당되어 있는 값으로 온전히 평가된다.
자바스크립트에서는 기본적으로 false로 간주되는 값들이 있는데, 바로 숫자 0, ''(빈 문자열), NaN, null, undefined이다. 연산자 || 는 실제로 직접 할당된 값이 false가 아니더라도 false로 간주되는 값이 || 의 앞에 위치하면 해당 값을 false로 처리하여 반드시 || 의 뒤에 있는 값을 반환한다.
console.log(0 || nickName) // 'zubetcha'
console.log(0 || NaN) // NaN
console.log('' || 0) // 0
변수에 falsy한 값을 할당한 후 각 연산자 || 와 ?? 가 반환하는 값을 비교해보자.
💡 숫자 0 을 할당한 경우
let z = 0
console.log(z || 100) // 100
console.log(z ?? 100) // 0
💡 빈 문자열 '' 을 할당한 경우
let z = ''
console.log(z || 100) // 100
console.log(z ?? 100) //
💡 NaN 을 할당한 경우
let z = NaN
console.log(z || 100) // 100
console.log(z ?? 100) // NaN
💡 null 을 할당한 경우
let z = null
console.log(z || 100) // 100
console.log(z ?? 100) // 100
💡 undefined 를 할당한 경우
let z = undefined
console.log(z || 100) // 100
console.log(z ?? 100) // 100
각 연산자가 반환하는 값에서 알 수 있듯이, 연산자 || 은 변수 z에 할당한 값이 falsy한 값인지, truthy한 값인지를 확인하여 falsy한 값이면 무조건 || 뒤에 위치한 값을 반환하고 있다. 연산자 ?? 는 변수 z에 할당한 값이 null 또는 undefined 인지, 아닌지를 확인하여 ?? 앞에 위치한 값이 null 또는 undefined인 경우에만 ?? 뒤에 있는 값을 반환하고 있다.
단, nullish 병합 연산자 ?? 또한 || 와 같이 연산자의 앞에 위치한 값을 확인하므로 연산자 앞, 뒤에 모두 null 또는 undefined가 위치해 있더라도 연산자 앞에 있는 값이 null 또는 undefined 이면 반드시 연산자 뒤에 있는 값을 반환한다.
console.log(null ?? undefined) // undefined
console.log(undefined ?? null) // null