자바스크립트 논리연산자를 공부하다가 논리연산자 우선순위와 단락 평가를 알게 됐다. 배우면서 알게된 것을 기록해두려고 한다.
자바스크립트에서 논리연산자는 표현식을 반환한다.
자바스크립트에서 논리연산자 AND와 OR는 참과 거짓만 반환하는 게 아니라, 표현식 자체를 반환한다. 규칙은 다음과 같다.
- AND의 경우 왼쪽이 참 같은 값(Truthy)이면 오른쪽을 반환하고, 참 같은 값이 아니면 왼쪽을 반환한다.
- OR의 경우 왼쪽이 참 같은 값이면 왼쪽을 반환하고, 참 같은 값이 아니면 오른쪽을 반환한다.
논리 연산자 우선순위는 표에 의하면 AND는 6, OR는 5로 AND가 OR 보다 우선순위가 더 높다. 다음은 MDN 웹 문서에 나와 있는 예제다.
true || false && false // returns true, because && is executed first
(true || false) && false // returns false, because operator precedence cannot apply
하지만 (적어도 지금까지 내가 판단하기에) 위 예제 첫번째는 오류가 있다. 분명 우선순위에서 앞서는 논리 AND은 먼저 실행되지 않는 것처럼 보인다. 확인할 수 있도록 콘솔에서 예제를 입력해보자.
console.log()
의 반환 값은 undefined
이므로 거짓 같은 값(falsey)이다. &&
연산자가 정상적으로 먼저 실행됐다면, 좌측 표현식을 평가하고(즉, "am I executed?"
를 콘솔에 출력하고) 참 같은 값이 아니기 때문에 undefined
가 반환되고, 이후 좌측에 있는 true
와 ||
연산을 해서 true
가 최종 반환되어야 한다. 하지만 콘솔에 출력된 것은 없다. 즉, 뒤의 &&
은 실행되지 않았다(혹은 실행됐는데 확인할 수 없다..?).
뒤의 논리연산자가 실행되지 않은 이유는 단락 평가 때문이다.
놀랍게도 논리연산자의 우선순위는 단락 평가에 무시당한다.
단락 평가는 다음과 같은 규칙을 따른다.
- AND 연산일 때 좌측 표현식이 거짓이면 우측 표현식이 뭐든 평가하지 않는다.
- OR 연산일 때 좌측 표현식이 참이면 우측 표현식이 뭐든 평가하지 않는다.
논리연산이고 뭐고, 우선순위가 높아도, 단락 평가가 일어난 순간 그 뒤의 연산은 모두 무시된다.
어차피 논리연산해봤자 결과가 정해져있는데, 뒤에 건 봐서 뭣해?
라고 하고 자바스크립트 컴파일러(?)가 에너지를 아끼는 것이다.
단락 평가로 인해 주의해야 할 점
위와 같이 원래라면 참조 오류가 났어야 할 표현식도 평가되지 않고 그저 false
만 반환된다. 단락 평가되었기 때문이다.
따라서 AND와 OR을 사용해서 프로그래밍을 할 경우 단락 평가가 일어났을 때 단락 평가 이후의 표현식이 오류가 있는지 없는지 판단할 길이 없으므로 주의가 필요하다는 것을 알 수 있다.
아래는 AND 연산과 OR 연산의 조합에 따라 표현식이 어떤 순서로 평가되는지 쉽게 알기 위해 (급하게, 대충) 만든 예제이다. 논리연산자 우선순위, 단락평가의 개념이 헷갈린다면 참고해서 보면 좋겠다.
function log(logical, order) {
console.log(order);
return logical;
}
// ------------------ A || B && C ------------------
console.log(
log(true, "첫번째") || (log(true, "두번째") && log(true, "세번째"))
);
// 첫번째
// true
console.log(
log(true, "첫번째") || (log(true, "두번째") && log(false, "세번째"))
);
// 첫번째
// true
console.log(
log(true, "첫번째") || (log(false, "두번째") && log(false, "세번째"))
);
// 첫번째
// true
console.log(
log(true, "첫번째") || (log(false, "두번째") && log(true, "세번째"))
);
// 첫번째
// true
console.log(
log(false, "첫번째") || (log(true, "두번째") && log(true, "세번째"))
);
// 첫번째
// 두번째
// 세번째
// true
console.log(
log(false, "첫번째") || (log(true, "두번째") && log(false, "세번째"))
);
// 첫번째
// 두번째
// 세번째
// false
console.log(
log(false, "첫번째") || (log(false, "두번째") && log(true, "세번째"))
);
// 첫번째
// 두번째
// false
console.log(
log(false, "첫번째") || (log(false, "두번째") && log(false, "세번째"))
);
// 첫번째
// 두번째
// false
// ------------------ A && B || C --------------------
console.log(
log(true, "첫번째") && (log(true, "두번째") || log(true, "세번째"))
);
// 첫번째
// 두번째
// true
console.log(
log(true, "첫번째") && (log(true, "두번째") || log(false, "세번째"))
);
// 첫번째
// 두번째
// true
console.log(
log(true, "첫번째") && (log(false, "두번째") || log(false, "세번째"))
);
// 첫번째
// 두번째
// 세번째
// false
console.log(
log(true, "첫번째") && (log(false, "두번째") || log(true, "세번째"))
);
// 첫번째
// 두번째
// 세번째
// true
console.log(
log(false, "첫번째") && (log(true, "두번째") || log(true, "세번째"))
);
// 첫번째
// false
console.log(
log(false, "첫번째") && (log(true, "두번째") || log(false, "세번째"))
);
// false
console.log(
log(false, "첫번째") && (log(false, "두번째") || log(true, "세번째"))
);
// 첫번째
// false
console.log(
log(false, "첫번째") && (log(false, "두번째") || log(false, "세번째"))
);
// 첫번째
// false
참고 문헌
'프로그래밍-학습기록 > Javascript' 카테고리의 다른 글
클로저는 글로 적기 글렀어. (0) | 2021.02.15 |
---|---|
자바스크립트 콜백 함수 이해하기 (0) | 2021.02.13 |
[Javascript] 다양한 상황에서 this는 무엇을 가리킬까 (0) | 2021.02.12 |
자바스크립트에서 실행 컨텍스트(execution context)가 도대체 뭐하는 애에요 (0) | 2021.02.10 |
자바스크립트 데이터 타입(기본형, 참조형) 이해하기 (0) | 2021.02.09 |