단락평가, 지름길 평가 (Short-circuit evaluation)

자바스크립트의 논리연산자를 기본 용도인 참/거짓의 판단을 위해 사용하는 것이 아닌, 조건문을 대체해 사용하는 일종의 문법 설탕 이라고 볼 수 있다.

기본원리

단락평가는 결국 조건연산자가 가진 아래의 두가지 특성을 응용한 것이다.

조건연산자의 좌결합성

and연산자(&&)와 or연산자(||) 모두 좌결합성을 가진다.
즉, 피연산자의 평가순서가 왼쪽부터 오른쪽 순으로 진행이 된다.

조건연산자의 평가결과

조건연산자는 Boolean 값을 반환하지 않는다.
최종적으로 평가된 피연산자의 평가결과를 반환한다.

&& - and

and 연산자의 경우 앞에 위치한 피연산자의 평가결과가 Falsy값일 경우
굳이 이후의 피연산자를 평가하지 않아도 false가 되기에
&& 연산자는 false로 평가된 피연산자 이후의 피연산자를 평가하지 않는다.

역으로 생각해보면 and 연산자는 앞에 위치한 피연산자의 평가결과가 Truthy값 이어야만,
뒤쪽의 피연산자를 평가하여 그 결과를 반환한다는 이야기가 된다.

용도1 : 조건문의 단축표현

condition && doSomething() 이라면 condition이 참일 때만 뒤 따라오는 doSomething을 호출한다.

1
2
3
4
5
6
7
8
9
10
// 1 condition이 true라면 doSomething 함수를 실행
if (condition) {
doSomething();
}

// 2 위 코드와 동일하다.
condition && doSomething();

// 3 좌결합성이기 때문에 조건을 계속 이어붙일 수 있다.
condition1 && condition2 && doSomething();

용도2 : null, undefined에 대한 대응

null이나 undefined인 값에 대해 .연산자나 []연산자를 통해 멤버접근을 시도하고자 하면, 속성을 읽을 수 없다는 내용의 TypeError 가 발생한다.

&& 연산자를 활용하면 이를 예방할 수 있다.

1
2
3
const bark = (animal) => {
return animal && animal.sound;
}

animal이 null이나 undefined가 아닐 경우 animal.sound에 접근한다.
null, undefined 외의 데이터 타입에 대해서는 해당 멤버가 존재하지 않더라도 undefined 만을 반환할 뿐, TypeError가 발생하지 않는다.

|| - or

or 연산자의 경우 앞에 위치한 피연산자의 평가결과가 Truthy 값일 경우
굳이 이후의 피연산자를 평가하지 않아도 true가 되기에 || 연산자는 앞쪽의 피연산자의 평가결과를 그대로 반환하고 뒤쪽의 피연산자는 평가하지 않는다.

역으로 생각해보면 or 연산자는 앞에 위치한 피연산자의 평가결과가 Falsy값이라면, 무조건 뒤쪽의 피연산자를 평가하여 그 결과를 반환한다는 이야기가 된다.

용도1 : 조건문의 대용

아래의 예제는 and 조건문의 경우와 정확히 반대이다.
and 조건문이 어떤 condition이 참일 때 따라오는 피연산자를 호출하였다면,
or 조건문은 어떤 condition이 거짓일 때 호출한다.

1
2
3
4
5
6
7
8
9
10
// 1 condition이 false라면 doSomething 함수를 실행
if (!condition) {
doSomething();
}

// 2 위 코드와 동일하다.
condition || doSomething();

// 3 좌결합성이기 때문에 조건을 계속 이어붙일 수 있다.
condition1 || condition2 || doSomething();

용도2 : 기본값 설정

두 개의 피연산자가 있을 경우, 앞 부분이 falsy값일 때,
보통 undefined나 null인 경우 argument가 정상적으로 전달되지 않았다고 가정하고 뒷 부분의 피연산자를 평가해 기본값으로 사용한다.

1
2
3
4
5
6
7
8
9
const bark = (animal) => {
const sound = animal && animal.sound;
return sound || "호로로로롤";
}

// 혹은 &&와 같이 이어붙여서 사용하면.. (체이닝)
const bark = (animal) => {
return animal && animal.sound || "호로로로롤";
}

두 번째 코드의 경우 조건 연산자의 우선순위가 ||보다 && 가 높아서 아래와 같이 표현도 가능하지만, 좀 더 명확하게 괄호로 묶어서 표현하거나 위 처럼 별 개의 라인으로 구분지어 놓는 것이 좋을 것 같다.

용도3 : 여러 후보군 중 하나를 골라내야할 때

앞 부분에서 Truthy 값이 나오면 뒷 부분을 평가하지 않는다는 특성을 활용해, 있을지 없을지 보장할 수 없는 여러 후보군에 대해 존재하는 하나를 골라낼 때 활용이 가능하다.

각 피연산자들을 같은 용도의 여러 선택지들이라고 가정할 때, 기회비용이 작은 순으로 좌에서 우로 나열해야한다.

1
2
3
4
5
6
7
8
9
/*
새로 만들어진 newFunc가 가벼우니까 있으면 먼저 사용해보고,
없으면 어쩔 수 없지.. 무겁지만 기존의 legacyFunc라도 사용하자.
*/
(obj.newFunc || obj.legacyFunc)();

(Array.prototype.filter || SomePolyfill.filter)(
(v) => !!v;
);

주의사항

단락평가의 경우 용도야 만들면 다양하겠지만, 코드의 가독성과 간결성을 위해서가 아니라면 굳이 억지로 사용해서 문법 닌자가 되지 말자.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×