[JavaScript] Method Chaining (메서드 체이닝)
과제를 하던 중 함수의 return값을 사용하는 부분이 없는데도 this를 return하는 코드를 발견했다.
확장성을 위해 return을 해둔 것인가? 라는 생각이 들었는데 검색해보아도 명확한 해답을 찾지 못했다.
그래서 질문을 남겨보았다. 질문하자마자 method chaining을 위한 코드라는 답변을 달아주셨다.🙇♀️
✅Method Chaining
연속적인 코드 줄에서 개체의 Method를 반복적으로 호출하는 것을 의미한다.
Method가 객체를 반환하면 그 반환 값(객체)이 또 다른 Method를 호출할 수 있다.
Method Chaining is a programming strategy that simplifies and embellishes your code. It is a mechanism of calling a method on another method of the same object. (reference1 / reference2)
Example
가게(store)에는 enter, leave 메서드가 있다.
const store = {
name: "see you",
opacity: 30,
peopleCount: 0,
enter(n) {
this.peopleCount += n;
},
leave(n) {
this.peopleCount -= n;
}
};
만약 2명의 손님이 들어오고, 1명의 손님이 나가고 다시 2명의 손님이 들어왔다면 아래와 같이 구현할 수 있다.
store.enter(2);
store.leave(1);
store.enter(2);
이 경우 Method Chaining 을 사용하면 아래와 같이 사용할 수 있다.
store.enter(2).leave(1).enter(2);
과제에서는 this를 return 하였는데, this를 return하면 아래와 같이 chaining을 할 수 있다.
const Store = function () {
this.name = "see you";
this.opacity = 30;
this.peopleCount = 0;
};
Store.prototype.enter = function (n) {
this.peopleCount += n;
return this;
};
Store.prototype.leave = function (n) {
this.peopleCount -= n;
return this;
};
Store.prototype.showPeopleCount = function (n) {
console.log(this.peopleCount);
};
const thisStore = new Store();
thisStore.enter(2).leave(1).enter(2).showPeopleCount(); // 3
체이닝에 대해 찾아보다 Optional Chaining의 정보도 알게 되었다.
✅Optional Chaining ( ?. 옵셔널 체이닝)
ECMAScript2020에서 도입된 optional chaining 연산자 ?.는 좌항의 피연산자가 null 또는 undefined인 경우 undefined를 반환하고, 그렇지 않으면 우항의 프로퍼티 참조를 이어간다.
> The ?. operator is like the . chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression short-circuits with a return value of undefined. When used with function calls, it returns undefined if the given function does not exist.
옵셔널 체이닝 연산자는 객체를 가리키는 변수가 null 또는 undefined가 아닌지 확인하고 프로퍼티를 참조할 때 유용하다.
// querySelector(...) 호출 결과가 null인 경우 에러 발생
let html = document.querySelector('.my-element').innerHTML;
위의 사례에서 페이지에 존재하지 않는 요소에 접근해 요소의 정보를 가려오려면 문제가 발생하는데, 이때 optional chaining을 사용하여 문제를 해결할 수 있다.
Optional Chaining이 추가되기 전에는 이런 문제를 해결하기 위해 && 연산자를 사용했다고 한다.
let user = {}; // 주소 정보가 없는 사용자
alert( user && user.address && user.address.street ); // undefined, 에러가 발생하지 않습니다.
중첩 객체의 특정 프로퍼티에 접근하기 위해 거쳐야 할 구성요소들을 AND로 연결해 실제 해당 객체나 프로퍼티가 있는지 확인하는 방법을 사용했다고 한다. 하지만 이렇게 AND를 연결한다면 코드가 길어지게 될 것이다.
참고) 논리 연산자 &&는 좌항 피연산자가 false로 평가되는 Falsy값(false, undefined, null, 0, -0, NaN, '')이면 좌항 피연산자를 그대로 반환한다. 하지만 0이나 ''d은 객체로 평가될 때도 있다.
따라서 아래 코드처럼 Optional Chaining(옵셔널 체이닝)을 사용할 수 있다.
let user = {}; // 주소 정보가 없는 사용자
alert( user?.address?.street ); // undefined, 에러가 발생하지 않습니다.
단락 평가
?.는 왼쪽 평가대상에 값이 없으면 즉시 평가를 멈춘다. 참고로 이런 평가 방법을 단락 평가(short-circuit)라고 부른다.
그렇기 때문에 함수 호출을 비롯한 ?. 오른쪽에 있는 부가 동작은 ?.의 평가가 멈췄을 때 더는 일어나지 않는다.
< Optional Chaining(옵셔널 체이닝) 사용 주의점 >
🛑 Optional Chaining을 남용하지 말아야 한다.
?.는 존재하지 않아도 괜찮은 대상에만 사용해야 한다.
사용자 주소를 다루는 위 예시에서 논리상 user는 반드시 있어야 하는데 address는 필수 값이 아니다. 따라서 user.address?.street를 사용하는 것이 바람직하다. 실수로 인해 user에 값을 할당하지 않았다면 바로 알아낼 수 있도록 해야 합니다. 그렇지 않으면 에러를 조기에 발견하지 못하고 디버깅이 어려워진다.
🛑 ?.앞의 변수는 꼭 선언되어 있어야 한다.
변수 user가 선언되어있지 않으면 user?.anything 평가 시 에러가 발생한다.
// ReferenceError: user is not defined
user?.address;
옵셔널 체이닝은 선언이 완료된 변수를 대상으로만 동작한다.
Summary
옵셔널 체이닝 문법 ?.은 세 가지 형태로 사용할 수 있다.
- obj?.prop – obj가 존재하면 obj.prop을 반환하고, 그렇지 않으면 undefined를 반환
- obj?.[prop] – obj가 존재하면 obj[prop]을 반환하고, 그렇지 않으면 undefined를 반환
- obj?.method() – obj가 존재하면 obj.method()를 호출하고, 그렇지 않으면 undefined를 반환
- ?. 왼쪽 평가 대상이 null이나 undefined인지 확인하고 null이나 undefined가 아니라면 평가를 계속 진행한다.
- ?.를 계속 연결해서 체인을 만들면 중첩 프로퍼티들에 안전하게 접근할 수 있다.
- ?.은 ?.왼쪽 평가대상이 없어도 괜찮은 경우에만 선택적으로 사용해야 한다.
- 꼭 있어야 하는 값인데 없는 경우에 ?.을 사용하면 프로그래밍 에러를 쉽게 찾을 수 없으므로 이런 상황을 만들지 말도록 한다.