자바스크립트엔 세 종류의 논리 연산자 ||
(OR), &&
(AND), !
(NOT)이 있다.
연산자에 '논리'라는 수식어가 붙긴 하지만 논리 연산자는 피연산자로 불린형뿐만 아니라 모든 타입의 값을 받을 수 있다. 연산 결과 역시 모든 타입이 될 수 있다.
'OR'연산자는 두 개의 수직선 기호로 만들 수 있다.
result = a || b;
전통적인 프로그래밍에서 OR 연산자는 불린값을 조작하는 데 쓰인다. 인수 중 하나라도 ture
이면 true
를 반환하고, 그렇지 않으면 false
를 반환한다.
자바스크립트의 OR 연산자는 다루긴 까다롭지만 강력한 기능을 제공한다. OR을 어떻게 응용할 수 있는지 알아보기 전에 먼저, OR 연산자가 불린값을 어떻게 다루는지 알아보도록 하자.
OR 연산자는 이항 연산자이므로 아래와 같이 네 가지 조합이 가능하다.
alert( true || true ); // true
alert( false || true ); // true
alert( true || false ); // true
alert( false || false ); // false
피연산자가 모두 false
인 경우를 제외하고 연산 결과는 항상 true
이다.
피연산자가 불린형이 아니면, 평가를 위해 불린형으로 변환된다.
예를 들어, 연산 과정에서 숫자 1
은 true
로, 숫자 0
은 false
로 바뀐다.
if (1 || 0) { // if( true || false ) 와 동일하게 동작하낟.
alert('truthy!');
}
OR 연산자 ||
은 if
문에서 자주 사용된다. 주어진 조건 중 하나라도 참
인지를 테스트하는 용도로 말이다.
예)
let hour = 9;
if (hour < 10 || hour > 18) {
alert( '영업시간이 아닙니다.' );
}
if
문 안에 여러 가지 조건을 넣을 수 있다.
let hour = 12;
let isWeekend = true;
if (hour < 10 || hour > 18 || isWeekend) {
alert( '영업시간이 아닙니다.'); // 주말이기 때문
}
지금까진 피연산자가 불린형인 경우만 다뤘다. 전통적인 방식이다.
이제 자바스크립트에서만 제공하는 논리연산자 OR의 '추가'기능에 대해 알아보자.
추가 기능은 아래와 같은 알고리즘으로 동작한다.
OR 연산자와 피연선자가 여러 개인 경우:
result = value1 || value2 || value3;
이때, OR ||
연산자는 다음 순서에 따라 연산을 수행한다.
true
이면 연산을 멈추고 해당 피연산자의 변환 전 원래 값을 반환한다.fasle
로 평가되는 경우)엔 마지막 피연산자를 반환한다.여기서 핵심은 반환 값이 형 변환을 하지 않은 원래 값이라는 것이다.
정리해 보자면 이렇다. OR "||"
연산자를 여러 개 체이닝(chaining)하면 첫 번째 truthy를 반환한다. 피연산자에 truthy가 하나도 없다면 마지막 피연산자를 반환한다.
예)
alert( 1 || 0 ); // 1 (1은 truthy)
alert ( null || 1 ); // 1 (1은 truthy)
alert ( null || 0 || 1 ); // 1 (1은 truthy)
alert ( undefined || null || 0 ); // 0 (모두 falsy이므로, 마지막 값을 반환함.
이런 OR 연산자의 추가 기능을 이용하면 여러 용도로 OR 연산자를 활용할 수 있다.
1. 변수 또는 표현식으로 구성된 목록에서 첫 번째 truthy 얻기
firstName
, lastName
, nickName
이란 변수가 있는데 이 값들은 모두 옵션 값이라고 해보자.
OR||
을 사용하면 실제 값이 들어있는 변수를 찾고, 그 값을 보여줄 수 있다. 변수 모두에 값이 없는 경우엔 익명
을 보여준다.
let firstName = "";
let lastName = "";
let nickName = "바이올렛";
alert( firstName || lastName || nickName || "익명" ); // 바이올렛
모든 변수가 falsy 이면 "익명"
이 출력되었을 것이다.
단락 평가
OR 연산자 ||
가 제공하는 또 다른 기능은 '단락 평가(short circuit evaluation)' 이다.
위에서 설명한 내용과 같이 OR||
은 왼쪽부터 시작해서 오른쪽으로 평가를 진행하는데, truthy를 만나면 나머지 값들은 건드리지 않은 채 평가를 멈춘다. 이런 프로세스를 '단락 평가'라고 한다.
단락 평가의 동작 방식은 두 번째 피연산자가 변수 할당과 같은 부수적인 효과(side effect)를 가지는 표현식 일 때 명확히 볼 수 있따.
아래 예시를 실행하면 두 번째 메시지만 출력된다.
true || alert("not printed");
false || alert("printed");
첫 번째 줄의 ||
연산자는 true
를 만나자마자 멈추기 때문에 alert
를 실행하지 않는다.
단락 평가는 연산자의 왼쪽 조건이 falsy일 때만 명령어를 실행하고자 할 때 자주 쓰인다.
두 개의 앰퍼샌드를 연달아 쓰면 AND 연산자 &&
를 만들 수 있다.
result = a && b;
전통적인 프로그래밍에서 AND 연산자는 두 피연산자가 모두 참일 때 true
를 반환한다. 그 외의 경우는 false
를 반환한다.
alert( true&&true ); // true;
alert( false&&true ); // false;
alert( true&&false ); // false;
alert( false&&false ); // false;
아래는 if
문과 AND 연산자를 함께 활용한 예제이다.
let hour = 12;
let minute = 30;
if (hour == 12 && mibute == 30) {
alert(' 현재 시각은 12시 30분입니다.' );
}
OR 연산자와 마찬가지로 AND 연산자의 피연산자도 타입에 제약이 없습니다.
if ( 1&&0 ) { // 피연산자가 숫자형이지만 논리형으로 바뀌어 true && false가 된다.
alert( "if 문 안에 falsy가 들어가 있으므로 alert창은 실행되지 않는다." );
}
AND 연산자와 피연산자가 여러 개인 경우를 살펴보자.
result = value1 && value2 && value3;
AND 연산자 &&
는 아래와 같은 순서로 동작한다.
false
이면 평가를 멈추고 해당 피연산자의 변환 전 원래 값을 반환한다.true
로 평가되는 경우)엔 마지막 피연산자가 반환된다. 정리해 보자면 AND 연산자는 첫 번째 falsy를 반환한다. 피연산자에 falsy가 없다면 마지막 값을 반환한다.
위 알고리즘은 OR 연산자의 알고리즘과 유사하다. 차이점은 AND 연산자가 첫 번째 falsy를 반환하는 반면, OR 연산자는 첫 번째 truthy를 반환한다는 것이다.
예)
// 첫 번째 피연산자가 truthy이면,
// AND는 두 번째 피연산자를 반환한다.
alert( 1&&0 ); // 0
alert( 1&&5 ); // 5;
// 첫 번째 피연산자가 falsy이면,
// AND는 첫 번재 피연산자를 반환하고, 두 번째 피연산자는 무시한다.
alert( null & 5 ); // null
alert( 0 && "아무거나 와도 상관없다." ); // 0
AND 연산자에도 피연산자 여러 개를 연속해서 전달할 수 있다. 첫 번째 falsy가 어떻게 반환되는지 예시를 통해 살펴보자.
alert( 1 && 2 && null && 3 ); // null
아래 예시에선 AND 연산자의 피연산자 모두 truthy이기 때문에 마지막 피연산자가 반환된다.
alert( 1 && 2 && 3 ); // 마지막 값, 3
&&
의 우선순위가 ||
보다 높다.AND 연산자 &&
의 우선순위는 OR 연산자 ||
보다 높다.
따라서 a && b || c && d
는 (a && b) || (c && d)
와 동일하게 동작한다.
if
를 ||나 &&로 대체하지 말기어떤 개발자들은 AND 연산자 &&
를 if
문을 '짧게' 줄이는 용도로 사용하곤 한다.
예)
let x = 1;
(x > 0) && alert( '0보다 큽니다!' );
&&
의 오른쪽 피연산자는 평가가 &&
우측까지 진행되어야 힐행된다. 즉, (x > 0)
이 참인 경우에만 alert
문이 실행된다.
위 코드를 if 문을 써서 바꾸면 다음과 같다.
let x = 1;
if (x > 0) alert( '0보다 큽니다!' );
&&
를 사용한 코드가 더 짧긴 하지만 if
문을 사용한 예시가 코드에서 무엇을 구현하고자 하는지 더 명백히 드러내고, 가독성도 좋다. 그러니 if 조건문이 필요하면 if
를 사용하고 AND 연산자는 연산자 목적에 맞게 사용하자.
논리 연산자 NOT은 느낌표 !
를 써서 만들 수 있다.
NOT 연산자의 문법은 매우 간단하다.
result = !value;
NOT 연산자는 인수를 하나만 받고, 다음 순서대로 연산을 수행한다.
1. 피연산자를 불린형 (true / false)
으로 변환한다.
2. 1에서 변환된 값의 역을 반환한다.
예)
alert( !true ); // false
alert( !0 ); // true
NOT 두 개를 연달아 사용 (!!)
하면 값을 불린형으로 변환할 수 있다.
alert( !!"non-empty string" ); // true
alert( !!null ); // false
이때, 첫 번째 NOT 연산자는 피연산자로 받은 값을 불린형으로 변환 후 이 값의 역을 반환하고, 두 번째 NOT 연산자는 첫 번째 NOT 연산자가 반환한 값을의 역을 반환한다. 이렇게 NOT을 연달아 사용하면 특정 값을 불린형으로 변환할 수 있다.
참고로, 내장 함수 Boolean
을 사용하면 !!
을 사용한 것과 같은 결과를 도출할 수 있다.
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // fasle
NOT
연산자의 우선순위는 모든 연산자 중에서 가장 높기 때문에 항상 &&
나 ||
보다 먼저 실행됩니다.
아래 코드의 결과를 예측해보자.
alert ( null || 2 || undefined );
피연산자 중 첫 번째 truthy인 2
가 출력된다.
아래 코드의 결과를 예측해보자.
alert( alert(1) || 2 || alert(3) );
얼럿 창엔 1
, 2
가 차례대로 출력된다.
alert( alert(1) || 2 || alert(3) );
alert
메서드는 값을 반환하지 않는다. 즉, undefined
를 반환한다.
1. 첫 번째 OR ||
은 왼쪽 피연산자인 alert(1)
를 평가한다. 이때 첫 번째 얼럿 창에 1
이 출력된다.
2. alert
메서드는 undefined
를 반환하기 때문에, OR 연산자는 다음 피연산자를 평가하게 된다. truthy 를 찾기위해 말이다.
3. 두 번째 피연산자(오른쪽 피연산자)인 2
는 truthy이기 때문에 실행을 멈추고 2
가 반환된다. 반환된 값 2
는 제일 바깥 alert
의 피연산자가 되어 두 번째 얼럿창에 출력된다.
평가가 alert(3)
까지 진행되지 않기 때문에 3
은 출력되지 않는다.
아래 코드의 결과를 예측해보자.
alert( 1 && null && 2 );
피연산자 중 첫 번째 falsy인 null
이 출력된다.
아래 코드의 결과를 예측해보자.
alert( alert(1) && alert(2) );
얼럿 창엔 1
, undefiend
가 차례대로 출력된다.
alert
를 호출하면 undefined
가 반환된다. alert
는 단순히 얼럿 창에 메시지만 띄워주고, 의미 있는 값을 반환해주지 않는다.
&&
는 왼쪽 피연산자를 평가하고(이때 1
이 얼럿창에 출력된다.) 평가를 즉시 멈춘다. alert(1)
의 평과 결과는 undefined
로 falys이기 때문이다. &&
연산자는 falsy를 만나면 그 값을 출력하고 즉시 연산을 멈춘다.
아래 코드의 결과를 예측해보자.
alert( null || 2 && 3 || 4 );
얼럿 창엔 3
이 출력됩니다.
AND 연산자 &&
의 우선순위는 ||
보다 높다. 따라서 &&
가 먼저 실행된다.
2 && 3 = 3
이므로, 문제에서 제시한 표현식은 아래와 같이 바꿔쓸 수 있다.
null || 3 || 4
따라서 첫 번째 truthy인 3
이 출력된다.
age
(나이)가 14
세 이상 90
세 이하에 속하는지를 확인하는 if
문을 작성해보자.
"이상과 이하"는 age
(나이) 범위에 14
나 90
이 포함된다는 의미이다.
if (age >= 14 && age <= 90) {
alert('실행합니다');
}
age
(나이)가 14
세 이상 90
세 이하에 속하지 않는지를 확인하는 if
문을 작성해보자.
답안은 NOT !
연산자를 사용한 답안과 사용하지 않은 답안 2가지를 제출하자.
if(!(age >= 14 && age <=90) ) {
...
}
if (age < 14 || age > 90)
아래 표현식에 어떤 alert
가 실행될까?
if(...)
안에 표현식이 있으면 어떤 일이 일어날까?
if (-1 || 0) alert( 'first' );
if (-1 && 0) alert( 'second' );
if (null || -1 && 1) alert( 'third' );
첫 번째 표현식과 세 번째 표현식이 있는 alert
가 실행된다.
이유:
// -1 || 0 은 -1 이므로 truthy 이다.
// 따라서 alert가 실행된다.
if (-1 || 0) alert( 'first' );
// -1 && 0 은 0이므로 falsy 이다.
// 따라서 alert가 실행되지않는다.
if (-1 && 0) alert( 'second' );
// 연산자 &&는 ||보다 우선순위가 높다.
// 따라서 -1 && 1 이 먼저 실행되어 아래와 같이 표현식이 순차적으로 바뀐다.
// null || -1 && 1 -> null || 1 -> 1
// 결과적으로 alert가 실행된다.
if (null || -1 && 1) alert( 'third' );
프롬프트(prompt)
대화상자를 이용해 간이 로그인 창을 구현해보자.
사용자가 "Admin"
를 입력하면 비밀번호를 물어보는 프롬프트 대화상자를 띄우자. 이때 아무런 입력도 하지 않거나 ESC
를 누르면 "취소되었습니다." 라는 메시지를 띄우자. 틀린 비밀번호를 입력했다면 "인증에 실패했습니다."라는 메시지를 보여주자.
비밀번호 확인 절차는 다음과 같다.
중첩 if
블록을 사용하고, 코드 전체의 가독성을 고려해 답안을 작성하자.
힌트: 프롬프트 창에 아무것도 입력하지 않으면 빈 문자열인 ''
가, ECS
를 누르면 null
이 반환된다.
let name = prompt('사용자 이름을 입력해주세요!', '');
if (name == 'Admin') {
let pwd = prompt('비밀번호를 입력해주세요.', '');
if (pwd == 'TheMaster') {
alert('환영합니다.');
} else if(pwd == '' || pwd == null) {
alert('취소되었습니다.');
} else {
alert('인증에 실패하였습니다.');
}
} else if (name == '' || name == null) {
alert('취소 되었습니다.');
} else {
alert('인증되지 않은 사용자입니다.');
}