안녕하세요 여러분! 이 글에서 저는 여러분께 고급 자바스크립트 연산자 세 가지인 널병합(nullish coalescing), 옵셔널 체이닝(optional chaining), 그리고 구조 분해 할당(destructuring assignment)에 대해 가르쳐드리고자 합니다.

이 세 가지 연산자는 여러분의 코드를 더 명확하고 에러가 덜 발생하는 코드로 작성하는데 도움을 줄 것입니다.

널병합 연산자

자바스크립트 코드를 살펴볼 때 두 개의 물음표(??)를 사용한 표현식을 볼 수 있습니다. 아래 코드에서 확인해보세요:

console.log(username ?? "Guest");


두 개의 물음표는 좌변의 표현식이 null이나 undefined일 경우 오른쪽 표현식을 반환하는 논리 연산자입니다.

이 연산자는 널병합 연산자로도 알려져 있으며, JavaScript ES2020에서 새롭게 소개된 기능으로 null이나 undefined 값을 좀 더 간결하게 확인할 수 있게 해줍니다.

널병합 연산자 문법

널병합 연산자의 문법은 매우 간단합니다. 두 개의 피연산자 사이에 두 개의 물음표 ??를 배치합니다.

다음은 예시입니다:

let firstName = null;
let username = firstName ?? "Guest";
console.log(username); // "Guest"

위 코드는 firstName 변수의 값을 username 변수에 할당합니다.

firstName 값이 null이나 undefined일 경우, 대신 “Guest” 값을 username 변수에 할당합니다:

let username = undefined ?? "Guest";
console.log(username); // "Guest"

보시다시피 null이나 undefined 값을 확인하기 위해 if-else 문을 사용할 필요가 없습니다.

자바스크립트에 이 연산자가 필요한 이유

널병합 연산자는 OR 연산자 ||의 개선된 대안으로 만들어졌습니다.

OR 연산자는 좌변의 표현식이 거짓으로 평가될 때 기본값이나 대체값을 제공하고자 만들어졌습니다.

하지만 실제 사용 상황에서는 0과 빈 문자열(“”)과 같이 거짓으로 간주되는 값을 반환하길 원할 때가 있습니다.

OR 연산자를 사용하면 거짓으로 간주되는 값은 전혀 반환할 수 없습니다. 다음 예제를 고려해 보세요:

// empty string evaluates to false in JavaScript:
let firstName = "";
let username = firstName ?? "Guest";
console.log(username); // ""

// When you use OR operator:
username = firstName || "Guest";
console.log(username); // "Guest"

널병합 연산자는 숫자, 문자열, 객체를 포함한 모든 유형의 값과 함께 사용될 수 있습니다.

널병합 연산자 사용 사례

널병합 연산자는 null이나 undefined 값을 확인하고 기본값을 제공해야 하는 다양한 상황에서 유용합니다.

다음은 몇 가지 흔한 사용 사례 예제입니다:

함수 인자 누락 처리

함수가 호출될 때 일부 인자가 생략될 수도 있습니다.

널병합 연산자는 누락된 인자에 기본값을 제공하는 데 사용될 수 있습니다:

//누락된 인자 처리를 위해 널병합 연산자를 사용하는 예
function greet(name) {
  console.log(`Hello, ${name ?? "Guest"}!`);
}

greet(); // 'Hello, Guest!'
greet("John"); // 'Hello, John!'

객체 속성 접근

객체를 다룰 때 특정 속성이 존재하지 않거나 undefined일 수 있습니다.

널병합 연산자는 객체 속성에 안전하게 접근하고 속성이 누락됐을 때 기본값을 제공하는 데 사용될 수 있습니다:

//undefined 객체 속성에 대한 대체값으로 널병합 연산자 사용
let user = { name: "John Doe" };
let email = user.email ?? "N/A";
console.log(email); // 'N/A'

변수와 상수 사이에서 선택
변수 값이 null이나 undefined일 경우, 변수 또는 상수에서 값을 선택하려면 다음과 같이 할 수 있습니다:

let value = null;
const DEFAULT_VALUE = 'Default';

let result = value ?? DEFAULT_VALUE;

console.log(result); // 'Default'

?? 연산자를 || 및 && 연산자와 함께 사용하기

안전상의 이유로 ?? 연산자는 자바스크립트의 OR (||) 및 AND (&&) 연산자와 괄호() 없이 함께 사용할 수 없습니다.

예를 들어, 다음 코드는 firstName 또는 lastName 변수를 사용하여 username의 값을 결정한 후 “Guest” 값을 사용하려고 합니다:

//논리적 OR을 사용할 때 널병합 연산자를 사용하는 예
let firstName = "John";
let lastName = "Stone";
let username = firstName || lastName ?? "Guest";
// Error: Unexpected token '??'

console.log(username);

이것은 자바스크립트가 어떤 연산자를 먼저 평가해야 하는지 결정할 수 없기 때문입니다. 괄호를 사용하여 평가의 우선 순위를 명확히 해야 합니다.

다음 코드는 괄호 안의 표현식을 먼저 평가합니다:

//논리적 OR을 사용할 때 괄호를 추가하는 예
let firstName = null;
let lastName = undefined;
let username = (firstName || lastName) ?? "Guest";

console.log(username); // "Guest"


이것이 어떻게 AND 또는 OR 연산자와 널병합 연산자를 결합하는지에 대한 것입니다.

옵셔널 체이닝 연산자

널병합 연산자와 마찬가지로 옵셔널 체이닝 연산자도 더 나은 방법을 제공하기 위해 새로 추가된 자바스크립트의 현대적인 기능입니다.

옵셔널 체이닝 연산자 ?.은 객체의 속성이나 메서드에 안전하게 접근할 수 있는 방법을 제공하며, 과정에서 오류를 피할 수 있습니다.

자바스크립트에서 가장 흔한 문제 중 하나는 undefined 값의 속성에 접근할 때 오류가 발생할 수 있다는 것입니다.

예를 들어, 다음과 같은 car 객체가 있다고 가정해 보겠습니다:

const car = {};

console.log(car.manufacturer); // undefined
console.log(car.manufacturer.address); //TypeError!


undefined 속성의 속성에 접근하면 오류가 발생합니다
위 예제에서, manufacturer 속성에 접근하면 undefined가 반환되지만, manufacturer 속성의 address 속성에 접근하려고 하면 자바스크립트는 오류를 반환합니다.

이것이 자바스크립트가 작동하는 방식이긴 하지만, 존재하지 않는 속성에 대해 오류를 반환하는 대신 undefined를 반환하는 것이 더 나은 방법일 것입니다.

이것이 옵셔널 체이닝 연산자가 만들어진 이유입니다. 연산자는 속성의 값이 있으면 그 값을 반환하고, 속성이 null이나 undefined일 경우 undefined를 반환합니다.

연산자를 사용하려면 점 표기법(.) 앞에 물음표를 추가하기만 하면 됩니다:

const car = {};

console.log(car.manufacturer?.address); // undefined


옵셔널 체이닝은 안전하게 undefined를 반환합니다
옵셔널 체이닝 연산자는 점 표기법을 사용하여 속성이나 메서드에 접근할 때마다 추가할 수 있습니다.

이 연산자를 사용하면 존재하지 않는 속성에서 속성을 접근하거나 메서드를 호출할 때 발생하는 TypeError를 피할 수 있습니다:

const car = {};

console.log(car.manufacturer?.address); // undefined
console.log(car.manufacturer?.drive()); // undefined


옵셔널 체이닝을 사용하여 TypeError 방지
옵셔널 체이닝 연산자는 이전의 값을 확인하는데만 사용된다는 점에 유의해야 합니다. car 변수가 null일 수 있다면, car 객체에 접근할 때 연산자를 추가해야 합니다.

다음 예를 참고하세요:

const car = null;

console.log(car?.manufacturer?.address); // undefined
console.log(car.manufacturer?.address); // TypeError: Cannot read properties of null

옵셔널 체이닝을 사용하여 객체가 undefined인지 확인
이것이 옵셔널 체이닝 연산자의 작동 방식입니다. 프로젝트에서 객체를 다룰 때 정말 유용합니다.

다음으로, 구조 분해 할당에 대해 알아봅시다.

구조 분해 할당 연산자

구조 분해 할당은 자바스크립트 배열과 객체의 값을 “풀어내거나” “추출”할 수 있게 해주는 특별한 연산자입니다. 두 가지 이유로 자바스크립트 언어에서 가장 유용한 기능 중 하나가 되었습니다:

  • 코드 반복을 피할 수 있습니다.
  • 코드를 깨끗하고 이해하기 쉽게 유지합니다.


다음으로 배열과 객체를 구조 분해하는 방법에 대해 알아보겠습니다.

배열 구조 분해

보통 다음과 같이 배열의 값을 변수에 할당합니다:

//대괄호 표기법을 사용하여 배열 요소에 접근
const sampleArray = ['Jane', 'John'];

const firstIndex = sampleArray[0];
const secondIndex = sampleArray[1];

위 코드는 동작합니다만, 배열에서 두 요소를 얻기 위해 두 줄의 코드가 필요합니다. 구조 분해 할당을 사용하면 한 줄로 배열의 요소를 변수에 할당할 수 있습니다:

//구조 분해 할당을 사용하여 배열 요소에 접근
const sampleArray = ['Jane', 'John'];

const [firstIndex, secondIndex] = sampleArray;


위 코드는 firstIndex와 secondIndex 변수에 동일한 값을 반환합니다. 당신이 얼마나 많은 요소를 가지고 있든, 구조 분해는 0 인덱스부터 시작됩니다.

구조 분해 할당을 만들려면 let/const 키워드 뒤에 대괄호 []를 추가해야 합니다. 대입(=) 연산자 뒤에 대괄호를 추가하면 배열이 됩니다. 대입 연산자 앞에 추가하면 구조 분해 할당이 됩니다.

또한 할당한 후 나머지 값을 복사하려면 나머지(rest) 연산자 …​을 사용할 수 있습니다. 다음 예를 보세요:

//구조 분해 할당에서 나머지 배열 값을 복사
const sampleArray = ['Jane', 'John', 'Jack', 'Aston'];

const [one, two, ...rest] = sampleArray;



rest 변수는 [‘Jack’,’Aston’] 값을 가진 배열을 포함할 것입니다.

추출된 값이 undefined일 경우, 이 변수들에 기본 값을 설정할 수도 있습니다:

//구조 분해 할당에 기본값 추가
const [a = 'Martin', b = 10] = [true];

// a는 true를 반환합니다
// b는 10을 반환합니다

또한 함수의 반환 값을 바로 할당에 사용할 수 있습니다. 이는 React와 같은 라이브러리에서 자주 사용됩니다:

//함수가 반환한 배열 구조 분해
const [a, b] = myFunction();

function myFunction() {
  return ['John', 'Jack'];
}


a 변수는 “John”을, b 변수는 “Jack”을 반환할 것입니다.

마지막으로, 일부 변수를 무시하고 할당을 생략하려면 해당 인덱스에 대한 할당을 건너뛸 수 있습니다:

//구조 분해 할때 요소 건너뛰기
const [a, , b] = [1, 2, 3];

// a는 1을 반환합니다
// b는 3을 반환합니다


구조 분해 할당은 배열 값의 풀기와 짧아진 반복으로 더 쉽고 짧게 만들어줍니다.

객체 구조 분해

배열과 마찬가지로 객체도 같은 방식으로 구조 분해할 수 있지만, 대괄호([]) 대신 중괄호({})를 사용해야 합니다:

//firstName 속성을 다른 변수 이름으로 할당
const user = {
  firstName: 'Jack',
  lastName: 'Smith',
};

const { firstName, lastName } = user;


주의할 점은 여전히 name과 lastName 두 변수만 생성한다는 것입니다. firstName은 name에 할당되므로 별도의 변수는 생성되지 않습니다.

배열처럼 함수가 반환하는 객체를 즉시 구조 분해할 수도 있습니다:

function myFunction() {
  return { firstName: 'Jack', lastName: 'Austin' };
}

const { firstName, lastName } = myFunction();

또는 다음과 같이 할 수 있습니다. 

function myFunction({ firstName, lastName }) {
  return firstName + ' ' + lastName;
}

const user = {
  firstName: 'Jack',
  lastName: 'Austin',
};

const name = myFunction(user);

결론

자바스크립트는 매년 지속적으로 발전하고 있으며, 이 글에서 설명한 세 가지 새 연산자는 자바스크립트 코드를 간략하고 더 안정적으로 작성할 수 있게 도와 주는 이제는 대부분의 프로그래머들이 매우 자주 쓰는 연산자입니다. 이에 대해 확실히 알아 두고 개발 시에 필요할 경우 반드시 사용할 수 있게 연습하는 것이 중요합니다.