본문으로 건너뛰기

&&·||·!

자바스크립트 목차조건레슨 17 / 76

목차

논리 연산자(logical operator) &&·||·! 셋은 조건을 잇거나 뒤집습니다. && 연산자(그리고)는 양쪽이 모두 참일 때만, || 연산자(또는)는 한쪽이라도 참이면 참이고, ! 연산자(아니다)는 참과 거짓을 뒤집습니다.

청소년 요금은 13세 이상이면서 19세 이하일 때 붙습니다. 비교 하나로는 이런 범위를 적을 수 없어 비교 둘을 && 연산자로 잇습니다.

6단계 중 1단계. 1번 줄: age를 10에 붙입니다.

1둘 다 참이어야 참인 &&

age >= 13 && age <= 19⁠는 비교 둘을 이은 식입니다. 비교가 먼저 묶이므로 괄호가 없어도 되고, 왼쪽 비교부터 접힙니다.

const age = 25;
if (age >= 13 && age <= 19) {
  console.log('청소년 요금');
} else {
  console.log('일반 요금');
}
실행 결과
일반 요금

25세는 왼쪽 25 >= 13이 true이지만 오른쪽 25 <= 19가 false라서 전체가 false입니다. &&·|| 연산자의 결과를 모두 적으면 이렇습니다.

왼쪽오른쪽&&||
truetruetruetrue
truefalsefalsetrue
falsetruefalsetrue
falsefalsefalsefalse

2한쪽만 참이어도 참인 ||

회원이거나 1만 원 이상 주문한 손님에게 쿠키를 줍니다.

const member = false;
const total = 14500;
if (member || total >= 10000) {
  console.log('쿠키 증정');
}
실행 결과
쿠키 증정

member는 false이지만 오른쪽 14500 >= 10000이 true라서 전체가 true입니다.

3참과 거짓을 뒤집는 !

! 연산자는 바로 뒤 값의 참과 거짓을 뒤집습니다.

const member = false;
console.log(!member);
if (!member) {
  console.log('회원 가입 안내');
}
실행 결과
true
회원 가입 안내

여럿을 섞어 쓰면 계산과 비교가 먼저 묶이고, 그다음 &&, 마지막에 || 연산자 차례로 묶입니다. ! 연산자는 바로 뒤 값 하나에 붙으니, 비교를 뒤집을 때는 !(age >= 20)처럼 괄호로 감쌉니다.

4왼쪽만으로 답이 나면 오른쪽은 계산하지 않는다

&& 연산자는 왼쪽이 false면 오른쪽이 무엇이든 false입니다. 그래서 오른쪽은 계산하지 않습니다. || 연산자는 왼쪽이 true면 오른쪽을 보지 않습니다. 이것을 단락 평가(short-circuit evaluation)라고 부릅니다.

아래 boom은 만든 적 없는 이름이라, 부르면 ReferenceError가 납니다. 이 코드는 무엇을 찍을까요? 답을 정한 뒤 펼쳐 보세요.

console.log(true || boom());
실행 결과 보기
실행 결과
true

예상과 다르면 그곳이 배울 곳입니다. 왼쪽이 true라서 || 연산자의 답은 이미 true입니다. 오른쪽 boom()은 부르지 않아 오류도 나지 않습니다.

5마지막으로 계산한 값을 돌려준다

&&·|| 연산자는 true·false를 새로 만들지 않고, 마지막으로 계산한 쪽의 값을 그대로 돌려줍니다. 양쪽이 비교면 그 값도 true·false라 차이가 보이지 않았을 뿐입니다.

console.log(false || 2);
console.log(true && 7);
console.log(false && 7);
실행 결과
2
7
false

1·2번 줄은 왼쪽만으로 답이 나지 않아 오른쪽까지 계산했고, 그 값을 돌려줍니다. 3번 줄은 왼쪽 false만으로 답이 나서 그 false를 돌려줍니다. 조건 자리에서 수는 0과 NaN만 거짓으로, 나머지는 참으로 칩니다. 어떤 값을 참으로 치는지는 다음 레슨에서 모아 봅니다.

예제

청소년이거나 회원이면 커피를 500원 싸게 팝니다. 고르기의 세 걸음으로 썼습니다. 4~5번 줄은 한 문장입니다. 폰 화면에 맞추려고 등호 뒤에서 줄을 나눴습니다.

const age = 15;
const member = false;
// 1. 조건 세우기
const teen =
  age >= 13 && age <= 19;
const cheap = teen || member;
// 2. 갈래마다 할 일
let price = 4000;
if (cheap) {
  price = 3500;
}
// 3. 갈래 뒤 공통
console.log(`커피 ${price}원`);
실행 결과
커피 3500원
  • 1. 조건 세우기: 청소년인지에 깃발 teen을, 할인 대상인지에 깃발 cheap을 붙입니다. 15세라 둘 다 true입니다.
  • 2. 갈래마다 할 일: cheap이 true면 price를 3500에 다시 붙입니다.
  • 3. 갈래 뒤 공통: 어느 갈래를 지났든 커피 값을 찍습니다.

자주 틀리는 곳

틀린 생각: &&·|| 연산자는 늘 양쪽을 다 계산한다.

+·- 계산처럼 양쪽을 다 구할 것 같습니다. 그러나 양쪽을 바꿔 쓰기만 해도 결과가 달라집니다.

console.log(false && boom());
console.log(boom() && false);
실행 결과
falsemain.js:2console.log(boom() && false);        ^ ReferenceError: boom is not defined    at main.js:2:9

1번 줄은 왼쪽 false만으로 답이 나서 boom()을 부르지 않았고, 2번 줄은 왼쪽 boom()부터 계산하다 멈췄습니다.

맞는 규칙: && 연산자는 왼쪽이 거짓이면, || 연산자는 왼쪽이 참이면 오른쪽을 계산하지 않습니다. 그래서 오류가 날 수 있는 식은 그것을 막는 조건의 오른쪽에 둡니다.

틀린 생각: x === 1 || 2는 'x가 1이나 2인가'를 묻는다.

말로 할 때는 x를 한 번만 말합니다. 그러나 || 연산자의 오른쪽 2는 비교가 아니라 수 하나입니다.

const x = 3;
console.log(x === 1 || 2);
if (x === 1 || 2) {
  console.log('1이나 2');
}
실행 결과
2
1이나 2

2번 줄은 왼쪽 3 === 1이 false라 오른쪽 값 2를 그대로 돌려줍니다(5절). 조건 자리의 2는 참이라, 3번 줄의 조건은 x가 무엇이든 늘 참입니다.

맞는 규칙: || 연산자는 왼쪽이 거짓이면 오른쪽 값을 그대로 돌려줍니다. 그래서 양쪽에 비교를 다 써서 x === 1 || x === 2로 묻습니다.

틀린 생각: && 연산자 뒤에서는 앞에 쓴 이름을 다시 쓰지 않아도 된다.

'13 이상이고 19 이하'도 말로는 나이를 한 번만 말합니다.

const age = 15;
console.log(age >= 13 && <= 19);
실행 결과
main.js:2console.log(age >= 13 && <= 19);                         ^^ SyntaxError: Unexpected token '<='

Unexpected token '<='⁠는 '여기서 <=는 뜻밖이다', 곧 && 연산자 바로 뒤에 새 식이 아니라 <= 기호가 왔다는 뜻입니다.

맞는 규칙: &&·|| 연산자의 양쪽은 저마다 값 하나로 접히는 식이어야 합니다. 오른쪽에도 이름을 다시 써서 age >= 13 && age <= 19⁠로 씁니다.

확인 문제

1. 예제의 age를 20으로 바꿨습니다. 무엇이 찍히는지 그대로 쓰세요.

const age = 20;
const member = false;
// 1. 조건 세우기
const teen =
  age >= 13 && age <= 19;
const cheap = teen || member;
// 2. 갈래마다 할 일
let price = 4000;
if (cheap) {
  price = 3500;
}
// 3. 갈래 뒤 공통
console.log(`커피 ${price}원`);
힌트

'1. 조건 세우기' — teen의 비교 둘을 하나씩 접은 뒤 && 연산자로 잇습니다.

정답
실행 결과
커피 4000원

20 >= 13은 true이지만 20 <= 19가 false라서 teen은 false입니다. cheap은 false || false라서 false이고, price는 4000 그대로입니다.

흔한 오답은 커피 3500원입니다. 왼쪽 비교 하나가 참이라 && 전체가 참이라고 본 것입니다.

2. 65세 이상이면 senior가 true, 65세 이상이거나 회원이면 cheap이 true가 되게 하려 합니다. 빈칸 둘을 채우고, 이 코드가 무엇을 찍는지도 쓰세요.

const age = 70;
const member = false;
const senior = age ___ 65;
const cheap = senior ___ member;
console.log(cheap);
힌트

첫 빈칸은 '이상'을 뜻하는 비교이고, 둘째 빈칸은 '이거나'를 뜻하는 논리 연산자입니다.

정답

차례로 >= 연산자와 || 연산자이고, true를 찍습니다. 70세라 senior가 true이고, cheap은 true || false라서 true입니다.

다르게 써도 되는 곳: 나이를 정수로 적으므로 age > 64도 같은 범위입니다. member || senior처럼 양쪽을 바꿔도 같습니다.

흔한 오답은 둘째 빈칸의 && 연산자입니다. '이거나'를 && 연산자로 옮기면 회원이 아닌 70세는 cheap이 false가 됩니다.

3. 마트 앱이 주말에만 할인을 보이려 합니다. 요일은 월요일 1부터 일요일 7까지 수로 적습니다. 그런데 수요일(3)에도 주말 할인이 찍힙니다.

const day = 3;
if (day === 6 || 7) {
  console.log('주말 할인');
} else {
  console.log('평일 가격');
}
실행 결과
주말 할인

몇 번 줄을 어떻게 고쳐야 할까요?

힌트

2번 줄에서 || 연산자의 왼쪽과 오른쪽이 각각 무엇인지 보세요.

정답

2번 줄을 if (day === 6 || day === 7) {⁠로 고칩니다. 그러면 평일 가격이 찍힙니다.

고치기 전에는 day === 6이 거짓이면 오른쪽 7을 그대로 돌려주고, 7은 조건 자리에서 참이라 늘 참이었습니다.

다르게 고쳐도 되는 곳: 요일이 1~7뿐이라 if (day >= 6) {로 고쳐도 일곱 요일 모두 맞게 찍힙니다.

흔한 오답은 day === 6 && day === 7⁠입니다. 늘 거짓이라 주말에도 평일 가격이 찍힙니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. '자주 틀리는 곳' 둘째 코드(다섯 줄)를 main.js에 저장합니다. x를 1 · 2 · 3으로 바꿔 가며, 돌리기 전에 무엇이 찍힐지 먼저 적고 돌려서 맞춰 봅니다. 그다음 2·3번 줄의 x === 1 || 2를 x === 1 || x === 2로 고쳐 같은 일을 해 봅니다. 저장하고 돌리는 법은 내 컴퓨터에서 돌려 보기에 있습니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

자바스크립트 목차로