Programming/자바스크립트

[자바스크립트] 옵셔널 체이닝

코딩하는 랄로 2023. 10. 26. 09:05
반응형

옵셔널 체이닝이란

옵셔널 체이닝(optional chaining) 연산자는 ?.로써, 객체 내의 key 에 접근할 때 그 참조가 유효한지 아닌지를 판단하여 유효할 경우에만 참조하고 유효하지 않을 경우(null or undefined), 에러를 발생시키는 것이 아닌 undefined를 반환하는 연산자이다.

 

자바스크립트에서 객체의 값을 접근하는 경우가 많은데 객체마다 가지고 있는 키 값이 차이가 있다. 예를 들어, 어떤 학생은 전공에 대한 정보가 있을 수 있지만 어떤 학생은 전공에 대한 정보가 기입되어 있지 않을 수 있다.

const students = {
    John : {
        age : 20,
        grade : 1,
        fieldOfStudy : {
            major : 'computer',
            minor : 'economics',
        }
    },
    
    Lee : {
        age : 24,
        grade : 3,
    }
}

// 각 학생의 1 전공을 출력해라
console.log(students.John.fieldOfStudy.major); //computer
console.log(students.Lee.fieldOfStudy.major);
//TypeError : cannot read properties of undefined (reading 'fieldOfStudy')

 

위의 예시를 보면, 학생 Lee의 전공(fieldOfStudy)에 대한 프로퍼티가 없기 때문에 해당 프로퍼티는 undefined 값을 가진다. 이 때 undefined로 점표기법을 통해 무언가를 참조하려고 하기 때문에 에러가 발생하는 것이다.

 

이 때 옵셔널 체이닝을 사용하지 않고 에러가 발생하지 않도록 하기 위해서는 아래와 같이 코딩할 수 있다.

// 각 학생의 1 전공을 출력해라
console.log(students.John.fieldOfStudy && students.John.fieldOfStudy.major); //computer
console.log(students.Lee.fieldOfStudy && students.Lee.fieldOfStudy.major); //undefined

 

SCE 연산을 이용하여 fieldOfStudy가 undefined가 아닐 때만 major값을 참조하여 출력하도록 하는 코드이다. SCE 연산을 이용했음에도 코드가 꽤 긴것을 볼 수 있다. 만약, John 또는 Lee의 프로퍼티의 존재도 확실하지 않다면, 코드는 다음과 같이 더욱 더 늘어날 것이다.

// 각 학생의 1 전공을 출력해라
console.log(students.John && students.John.fieldOfStudy && students.John.fieldOfStudy.major); //computer
console.log(students.Lee && students.Lee.fieldOfStudy && students.Lee.fieldOfStudy.major); //undefined

 

중첩 객체의 수가 늘어날 수록 코드는 길어지고 가독성 또한 떨어진다. 이러한 상황에서 유용하게 사용할 수 있는 것이 바로 옵셔널 체이닝이다. 위의 예제를 옵셔널 체이닝을 변경하면 아래와 같다.

// 각 학생의 1 전공을 출력해라
console.log(students.John?.fieldOfStudy?.major); //computer
console.log(students.Lee?.fieldOfStudy?.major); //undefined

 

 

위의 SCE 연산을 사용한 코드와 같은 의미이지만, 코드는 훨씬 간편해진 것을 볼 수 있다. 옵셔널 체이닝 연산은, 연산자의 왼쪽에 있는 값이 nullish(null or undefined)값을 가지고 있다면 undefined를 반환하고 끝나지만 아니라면 오른쪽 참조한 값으로 넘어가 평가를 진행하는 것이다.

 

 

옵셔널 체이닝 장점

1. if문 사용의 감소

if문의 사용은 SCE 연산을 이용하여 줄일 수 도 있지만, 위의 예제에서 보았듯이 중첩 객체의 참조에서는 SCE연산조차도 간결하게 만드는 것이 옵셔널 체이닝이다.

const students = {
    John : {
        age : 20,
        grade : 1,
        fieldOfStudy : {
            major : 'computer',
            minor : 'economics',
        }
    },
    
    Lee : {
        age : 24,
        grade : 3,
    }
}

// 각 학생의 1 전공을 반환하는 함수
// if문 사용
function printMajorUsingIf(student) {
    if(student === undefined) return undefined;
    if(student.fieldOfStudy === undefined) return undefined;
    return student.fieldOfStudy.major;
}

console.log(printMajorUsingIf(students.John); //computer
console.log(printMajorUsingIf(students.Lee); //undefined

//SCE 연산 사용
function printMajorUsingSCE(student) {
    return student && student.fieldOfStudy && student.fieldOfStudy.major;
}

console.log(printMajorUsingSCE(students.John); //computer
console.log(printMajorUsingSCE(students.Lee); //undefined

//optional chaining
function printMajorUsingOptional(student) {
    return student?.fieldOfStudy?.major;
}

console.log(printMajorUsingOptional(students.John); //computer
console.log(printMajorUsingOptional(students.Lee); //undefined

 

2. nullish 연산자와 함께 사용하면 기본값 주기에 용이

nullish 연산은 처음 만나는 null or undefined 값을 가지지 않는 값을 반환한다. 이를 통해 다음과 같이 기본값을 줄 수 있다.

//optional chaining + nullish => 기본값 주기
function printMajorUsingOptional(student) {
    return student?.fieldOfStudy?.major ?? '전공 모르겠음'
}

console.log(printMajorUsingOptional(students.John); //computer
console.log(printMajorUsingOptional(students.Lee); //전공 모르겠음

 

3. 대괄호 표기법에서도 사용 가능

//대괄호 표기번 이용
function printMajorUsingOptional(student) {
    return student?.['fieldOfStudy']?.['major'] ?? '전공 모르겠음'
}

console.log(printMajorUsingOptional(students.John); //computer
console.log(printMajorUsingOptional(students.Lee); //전공 모르겠음

 

4. 존재하지 않는 메소드를 호출할 수 있는 경우에도 사용 가능

메소드를 검사하기 위해서는 의 인수를 넘기는 부분 앞쪽에 옵셔널 체이닝 연산자를 넣어준다. (ex. 함수명?.(arg1, arg2, ...) ) 

const john = {
    age : 20,
    printInfo : function () { console.log(`I'm John`); },
}

const lee = {
    age : 20,
}

function callFunc(person) {
    return person.printInfo?.() ?? 'no method';
}

callFunc(john); // I'm John
callFunc(lee);  // no method

 

만약 메소드가 아닌 프로퍼티를 위와 같이 사용한다면 함수가 아니라는 에러가 발생하니 주의하여야 한다.

 

5. 배열에도 사용 가능!!

자바스크립트에서는 배열의 존재하지 않는 index를 참조할 때, undefined를 호출하여 크게 의미 있지는 않지만, 배열에도 사용가능하다.

//배열도 사용 가능
const arr = [1, 2, 3, 4, 5];

console.log(arr?.[5] ?? 6); //6
console.log(arr[5]); //undefined

 

 

주의할 점

어떠한 언어이든, 특정 문법을 편하다고 남용하기 보다는 적절하게 필요할 때에만 써야 코드의 가독성과 디버깅 등이 더 편리해진다. 옵셔널 체이닝 또한 에러를 피하기 위해 남용하다보면, 디버깅이 어려워 질 수 있다.

 

예를 들어, 무조건 존재해야 하는 객체에 옵셔널 체이닝을 사용하게 되면 해당 객체가 없어 에러를 통해 발견할 수 있어야 하는 상황에 발견을 못하게 되는 문제가 발생할 수 있다. 즉, 옵셔널 체이닝은 존재하지 않아도 되는 객체에 사용해야 하는 것이다.

 

그렇기 때문에, 편리하더라도 남용하지 말고 상황에 맞춰서 사용하여야한다.

반응형