본문 바로가기
자바스크립트

Optional Chaining 연산자와 Nullish coalescing 연산자. 그리고 우선순위

by 찬찬2 2022. 6. 27.

[1] Optional Chaining 연산자 "?."

optional chaining 연산자는 체인의 각 참조가 유효한지 명시적으로 검증하지 않고, 연결된 객체 체인 내에 깊숙이 위치한 속성 값을 읽을 수 있다.

 

const obj = {
   a: {
      b: {
         c: {
            age: 12
         }
      }
   }
}

console.log(obj.a.b.c.age); // 12

 

이렇게 nesting 이 된 객체에서 만약 age 의 값을 읽으려고 했을때 c 프로퍼티 바로 위 단계인 b 가 없는데 위와 같이 읽으려고 한다면? "Cannot read properties of undefined" 에러가 출력된다.

 

여기서 optional chaining 연산자의 진가를 볼 수 잇는데, 

 

console.log(obj.a?.c?.d?.age); // 12

 

우선 사용법은 위와 같다. "?." 연산자가 사용된 왼쪽 부터, 만약 a 가 있다면 후속적으로 만약 b 가 있다면... 이런식으로 고리(chaining) 처럼 위에서 부터 아래로 접근할 수가 있다.

 

- 함수의 호출과 Optional Chaining

존재하지 않을 수 있는 매서드를 호출할 때, optional chaining을 사용할 수 있다. 예를 들어, 구현 기간이나 사용자 장치에서 사용할 수 없는 기능 때문에 메서드를 사용할 수 없는 API를 사용할 경우,  유용할 수 있다.

함수 호출과 optional chaining을 사용함으로써 메서드를 찾을 수 없는 경우에 예외를 발생시키는 것 대신에 그 표현식은 자동으로 undefined를 반환한다.

 

function doSomething(onContent, onError) {
  try {
    // ... do something with the data
  }
  catch (err) {
    if (onError) { // Testing if onError really exists
      onError(err.message);
    }
  }
}

// Using optional chaining with function calls
function doSomething(onContent, onError) {
  try {
   // ... do something with the data
  }
  catch (err) {
    onError?.(err.message); // no exception if onError is undefined
  }
}

 

[2] 널 병합 연산자 Nullish coalescing → "??"

널 병합 연산자(??) 는 왼쪽 피연산자가 null 또는 undefined일 때 오른쪽 피연산자를 반환하고, 그렇지 않으면 왼쪽 피연산자를 반환하는 논리 연산자이다.

널 병합 연산자는 연산자 우선 순위가 다섯번째로 낮은데, || 의 바로 아래이며 조건부 연산자(삼항연산자)의 바로 위이다.

 

- 왼쪽아니면 오른쪽

?? 와 || 는 왼쪽의 피연산자의 값에 따라 그대로 왼쪽 값을 사용할 것인지 아니면 오른쪽 값을 사용할 것인지 결정해주는 역할은 같다.

 

- || 와 ?? 의 차이점은...

 

// OR 연산자
let resultA = null || 1;

console.log(result); // output: 1

resultA = 0 || 1;

console.log(result); // output: 1


// ?? 연산자
let resultB = null ?? 1;

console.log(resultB); // output: 1

resultB = 0 ?? 1;

console.log(resultB); // output: 0

 

OR 연산자의 경우 숫자 0을 null 또는 undefined 로 판단하여 오른쪽 값을 변수에 할당한다.

반대로 널 병합 연산자의 경우 0 을 변수에 할당하는 것을 볼 수 있다.

 

학생의 점수를 담고 있는 데이터베이스에서 A 학생이 0 이라는 점수를 실제로 가지고 있는 것과, 아직 점수가 채점되지 않아 NULL 의 데이터를 담고있을때 OR 연산자를 사용하면 코드를 실행하는데 있어 논리적인 오류가 발생한다.

 

점수가 0 이면 0을 가져와 활용하면 되고, 만약 NULL 이면 "점수가 아직 채점되지 않았습니다." 처럼 처리될 수 있을 것이다. 그렇기 때문에 숫자를 활용해야만 하는 상황에서는 OR 연산자가 적합하지 않다고 생각한다.

 

- 연산자의 우선순위

연산자를 다룰때 또 하나 중요한 점은 바로 우선순위 이다. 덥셈, 곱셈, 뺄셈, 나눗셈 과 같은 연산자에서 우선순위에 대한 개념은 알고 있다. 예를 들어 1 + 2 * 2 의 경우 덧셈 보다 곱셈이 우선순위를 가진다. 만약 내가 원하는 결과가 5 라면, 소괄호를 써서 2 * 2를 묶어주면 된다. 5가 아닌 6을 생각했다면 위 식 그대로 써도 될것이다.

 

자바스크립트는 정말 다양한 연산자를 가지고 있는데, 그 것들 모두 우선순위를 가지고 있다. 그렇다면 OR 연산자와 널 병합 연산자의 우선순위는 어떻게 될까. OR 연산자가 널 병합 연산자 보다 우선순위를 가지고 있다.

 

OR 연산자와 널 병합 연산자를 같이 활용하는 상황이 있다면 그 우선순위를 이해하고 사용해야한다.

아래 샘플코드를 보면 나는 result 변수에 "Hello" 라는 문자열 값을 할당하고 싶었다. 두 개의 예제를 보면, 결과적으로 "Hello" 를 변수에 담기는 했으나 연산자의 처리 과정이 다른 것을 볼 수 있다.

 

이렇게 숫자를 다루는 계산식에서의 연산자는 일상생활에서도 많이 쓰지만 논리식에서 사용하는 연산자는 생소하여 글을 써보았다.

 

// Example with logical OR (||) and nullish coalescing (??)
const a = null;
const b = "Hello";
const c = 0;
const d = "World";

// Operator precedence without parentheses
const result1 = a ?? b || c ?? d;
console.log(result1); // Expected output: "Hello"

// Explanation:
// Step-by-step evaluation due to precedence rules:
// 1. a ?? b          -> null ?? "Hello"        -> "Hello"     (nullish coalescing)
// 2. "Hello" || c    -> "Hello" || 0           -> "Hello"     (logical OR)
// 3. "Hello" ?? d    -> "Hello" ?? "World"     -> "Hello"     (nullish coalescing)


// Using parentheses to control precedence
const result2 = (a ?? b) || (c ?? d);
console.log(result2); // Expected output: "Hello"

// Explanation:
// Step-by-step evaluation due to parentheses:
// 1. (a ?? b)        -> (null ?? "Hello")      -> "Hello"     (nullish coalescing)
// 2. (c ?? d)        -> (0 ?? "World")         -> 0           (nullish coalescing)
// 3. "Hello" || 0    -> "Hello"                (logical OR)

 

MDN 연산자 우선순위

댓글