학습 자료

연산자 — 비교하고 판단한다


Article

5강에서 더하고 빼는 법을 배웠다. 이번에는 판단하는 법을 배운다.

"나이가 19살 이상인가?", "회원이면서 로그인 상태인가?" 같은 질문에 답을 내는 연산자들이다. 다음 강의에서 다룰 조건문의 재료가 되므로, 여기서 확실히 잡고 간다.

비교 연산자

두 값을 견주어 truefalse를 내놓는다. 4강에서 본 boolean이 여기서 나온다.

기호예시결과
>크다7 > 3true
<작다7 < 3false
>=크거나 같다3 >= 3true
<=작거나 같다3 <= 2false
===같다3 === 3true
!==다르다3 !== 4true

크기 비교는 직관적이다. 문제는 "같다"를 확인하는 쪽이다.

const age = 20;

console.log(age >= 19);
console.log(age === 20);
console.log(age !== 20);
콘솔
  • true
  • true
  • false

초보자가 가장 많이 내는 실수가 조건문에 =를 하나만 쓰는 것이다. 비교하려 했는데 값을 넣어버린다.

let score = 50;

// 비교하려 했지만 100 을 넣어버렸다
if (score = 100) {
  console.log("만점!");
}

console.log(score);
콘솔
  • 만점!
  • 100

score가 100으로 바뀌었고, 조건문도 통과해버렸다. 에러조차 나지 않는다. 눈으로 찾기 어려운 종류의 버그다.

문자열도 비교된다

문자열끼리 크기를 비교하면 사전 순서로 따진다.

console.log("apple" < "banana");
console.log("2" > "10");
console.log(2 > 10);
콘솔
  • true
  • true
  • false

두 번째 줄이 이상하다. 문자열 "2""10"을 비교하면 첫 글자 21을 견주고, 2가 더 크므로 true가 된다. 숫자로 비교한 세 번째 줄과 결과가 정반대다.

숫자처럼 생긴 문자열을 그대로 비교하면 이런 함정에 빠진다. 입력창에서 받은 값은 항상 문자열이라는 걸 기억해야 한다.

논리 연산자

조건 여러 개를 엮는다. 세 개뿐이다.

&& 와 || 와 !

&&

그리고 (AND)

  • 둘 다 참이어야 참
  • 하나라도 거짓이면 거짓
  • true && truetrue
  • true && falsefalse

||

또는 (OR)

  • 하나라도 참이면 참
  • 둘 다 거짓이어야 거짓
  • false || truetrue
  • false || falsefalse

!

아니다 (NOT)

  • 참과 거짓을 뒤집는다
  • !truefalse
  • !falsetrue
  • 혼자 쓰인다

실제로 쓰면 이렇다.

const age = 22;
const isMember = true;

console.log(age >= 19 && isMember);
console.log(age >= 30 || isMember);
console.log(!isMember);
콘솔
  • true
  • true
  • false

&&는 조건이 모두 맞아야 하니 까다롭고, ||하나만 맞아도 되니 너그럽다. 이렇게 외워두면 헷갈리지 않는다.

단축 평가 — 끝까지 보지 않는다

여기서부터가 자바스크립트의 진짜 모습이다. &&||답이 정해지는 순간 나머지를 보지 않는다.

false && ??? 를 만나면
  1. 01

    왼쪽을 본다

    false 다.

  2. 02

    결과가 이미 정해졌다

    && 는 둘 다 참이어야 한다. 왼쪽이 거짓이니 오른쪽이 무엇이든 결과는 거짓이다.

  3. 03

    오른쪽은 실행조차 하지 않는다

    그래서 오른쪽에 함수 호출을 두면 아예 호출되지 않는다.

    false && sendEmail();  // sendEmail 은 실행되지 않는다

||는 반대다. 왼쪽이 참이면 오른쪽을 건너뛴다.

더 놀라운 건 이 연산자들이 truefalse를 돌려주지 않는다는 점이다. 실제로 확인해보자.

console.log(0 || "기본값");
console.log("입력값" || "기본값");
console.log("안녕" && "반가워");
console.log(null && "실행 안 됨");
콘솔
  • '기본값'
  • '입력값'
  • '반가워'
  • null

boolean이 아니라 값 자체가 나온다. 규칙은 단순하다.

연산자동작돌려주는 값
||왼쪽이 참 같으면 멈춘다멈춘 지점의 값
&&왼쪽이 거짓 같으면 멈춘다멈춘 지점의 값

여기서 "참 같다"는 표현을 썼다. true가 아니어도 참처럼 취급되는 값들이 있기 때문인데, 이걸 truthy · falsy라 부른다. 다음 강의의 주인공이다. 지금은 거짓처럼 취급되는 값이 이것뿐이라는 것만 봐두자.

이 성질을 실무에서 쓴다

||로 기본값을 채우는 패턴을 아주 자주 만난다.

function greet(name) {
  const displayName = name || "손님";
  console.log(`안녕하세요, ${displayName}님`);
}

greet("지원");
greet();
greet("");
콘솔
  • 안녕하세요, 지원님
  • 안녕하세요, 손님님
  • 안녕하세요, 손님님

이름이 없으면 "손님"이 들어간다. 그런데 세 번째 호출이 문제다. 빈 문자열도 falsy라 기본값으로 바뀌어버렸다. 대개는 그게 원하는 동작이지만, 아닐 때도 있다.

const count = 0;
console.log(count || 10);
콘솔
  • 10

개수가 0인 게 맞는데 기본값 10으로 바뀌었다. 0이 falsy이기 때문이다. 이런 버그가 실제로 자주 난다.

?? — 진짜로 없을 때만

이 문제를 풀려고 나온 게 널 병합 연산자 ??다. ||와 거의 같지만, 왼쪽이 null이나 undefined일 때만 오른쪽을 쓴다.

const count = 0;
const name = "";

console.log(count || 10);
console.log(count ?? 10);

console.log(name || "손님");
console.log(name ?? "손님");
콘솔
  • 10
  • 0
  • '손님'
  • ''

??0""를 값으로 인정한다. "값이 아예 없을 때"와 "값이 0일 때"를 구분해야 한다면 ??를 쓴다.

언제 무엇을 쓰나

||

falsy 면 전부 대체

  • 0, "", false 도 대체된다
  • "비어 있으면 기본값" 에 알맞다
  • 숫자를 다룰 때 위험하다

??

null · undefined 만 대체

  • 0, "", false 는 그대로 둔다
  • "값이 없으면 기본값" 에 알맞다
  • 대부분 이쪽이 안전하다

우선순위

연산자가 섞이면 계산 순서가 생긴다. 수학의 곱셈이 덧셈보다 먼저인 것과 같다.

먼저 계산되는 순서
  1. ( )괄호
  2. !부정
  3. * / %곱셈류
  4. + -덧셈류
  5. > < >= <=크기 비교
  6. === !==같음 비교
  7. &&그리고
  8. ||또는

&&||보다 먼저다. 그래서 아래 두 줄은 같은 뜻이다.

const a = true, b = false, c = true;

console.log(a || b && c);
console.log(a || (b && c));
콘솔
  • true
  • true

외우려 하지 말고 헷갈리면 괄호를 친다. 괄호는 공짜고, 읽는 사람에게 의도를 알려준다.

정리하면

  • 비교 연산자는 true / false를 내놓는다. 같음은 반드시 ===로 확인한다.
  • 조건문에 =를 하나만 쓰면 비교가 아니라 할당이 된다. 에러도 안 난다.
  • &&는 까다롭고 ||는 너그럽다.
  • &&||는 boolean이 아니라 멈춘 지점의 값을 돌려준다. 그래서 기본값 패턴이 성립한다.
  • 0이나 ""를 값으로 인정해야 한다면 || 대신 **??**를 쓴다.

다음 강의에서는 미뤄둔 이야기를 마무리한다. truthy와 falsy가 정확히 무엇이고, 왜 ==를 쓰면 안 되는지 본다.

연산자 — 비교하고 판단한다 — 디코드랩(DCODELAB)