본문 바로가기

015. [기본] 논리 연산자(or &&, !not, 논리 연산자 우선순위)

codeConnection 2024. 3. 28.

원문

복습이 목적이라면 이 문서에서 연습문제 먼저 보는 것이 좋다. 연습문제의 품질이 좋다.

논리 연산자

논리 연산자 기능 의미
|| OR(원화표시) 이항 중 하나라도 참이면 true, 아니면 false
&& AND 이항 중 둘 다 참이어야 true, 아니면 false
! NOT 부호를 반대로 뒤집음

|| (OR) 연산자

|| 연산자 기본형

result = a || b;

a와 b 중 하나라도 true면 true를 반환하고, 아니면 둘 다 fasle면 false를 반환한다.

예시

console.log( true || true ); // true
console.log( true || false ); // false
console.log( false || true ); // true
console.log( false || false ); // false

주로 if문에서 많이 사용된다.

if ( 1 || 0 ) {
    console.log("truthy!");
} // truthy!
// 1은 truhty한 값, 0은 falsy한 값이다. 따라서 둘 중 하나가 true이므로 if의 조건문이 참이 되어 평가된다.

여러개도 중첩 가능하다.

let hour = 12;
let isWeekend = true;

if ( hour < 10 || hour > 18 || isWeekend ) {
    console.log( '영업시간이 아닙니다.' );
}
// hour가 10보다 작거나, hour가 18보다 크거나, isWeekend(주말인 상태)가 true이면
// 조건문이 실행되도록 했다.
// 10시 오픈, 18시 클로즈여서 그렇고, hour는 12로 영업시간이 맞지만, isWeekend 변수가 true 상태이므로
// 셋 중 하나라도 true이기 때문에 코드 블럭이 실행된다.

정리하자면 || 논리 연산자는 피연산자가 2개일 때와 3개 이상일 때 반환하는 값이 다르다.

  • 피연산자가 2개 일 때
    • 피연산자 중 truthy한 값이 하나라도 있으면 true를 반환하고, 둘 다 falsy한 값이라면 false를 반환한다.
  • 피연산자가 3개 이상일 때
    • 왼쪽부터 오른쪽으로 차례대로 피연산자를 비교해나간다.
    • truty한 값이 먼저 나오는 값의 원래의 값을 반환한다.
    • 만약 모두 falsy한 값이면 가장 마지막 피연산자의 원래의 값을 반환한다.

|| 논리 연산자의 추가 기능

첫번째 truthy한 값을 찾는 ||

위의 예제는 || 논리 연산자가 불린값들만 놓고 각 항에서 true나 truthy한 값이 하나라도 있으면 true를 반환하는 예제였다.

하지만 자바스크립트에서만 동작하는 추가 기능이 있다. 피연산자가 불린형이 아닌 경우에는 좌항부터 차례대로 비교해가며 가장 먼저 등장하는 truthy한 값을 반환한다.

|| 논리 연산자의 추가 기능 알고리즘
  1. 좌항에서부터 우측으로 진행하며 비교를 시작한다. (chaning)
  2. 첫번째 항과 두번째 항을 비교한다.
  3. 각 피연산자를 불린형으로 변환해서 truthy한 값이 나오면 그 값의 원래 값을 반환한다.
  4. 만약 피연산자가 모두 falsy한 값일 경우 가장 마지막 피연산자를 반환한다.
console.log( 1 || 0 ); // 1
// 1은 truthy, 0은 falsy한 값이다.
// 따라서 truthy한 값인 1을 반환한다.

console.log( null || 1 ); // 1
// 1은 역시 truthy한 값이다.

console.log( null || 0 || 1 ); // 1

console.log( undefined || null || 0 ); // 0
// 모두 falsy한 값이기 때문에 마지막 값인 0을 반환한다.
|| 논리 연산자의 실제 사용 예시
  1. 변수 또는 표현식으로 구성된 목록에서 첫번째 truthy한 값 얻기 (회원정보 등에서 공백이 없이 실제 데이터가 있는 값을 반환시키기)
let firstName = "";
let lastName = "";
let nickName = "바이올렛";

console.log( firstName || lastName || nickName || "정보없음"); // 바이올렛

객체 유저정보를 통해 값 얻기(직접 작성)
객체, 프로퍼티 호출법, 템플릿 리터럴 등에 대한 지식이 있어야 한다.

let user = {
    firstName : "",
    lastName : "",
    nickName : "바이올렛"
};

let message = `
${user.firstName || user.lastName || user.nickName || "익명"} 회원님 안녕하세요!
`;

console.log(message); // 바이올렛 회원님 안녕하세요!

단락평가 (short circuit evaluation)

단락평가라는 것은 || 논리 연산자가 피연산자를 왼쪽부터 오른쪽으로 truthy한 값을 찾아 비교를 진행하다가,
truthy한 값을 찾게 되면 더이상 비교를 진행하지 않고 멈추는 것을 말한다.

true || console.log("안녕하세요"); // 작동안함
false || console.log("안녕하세요"); // 안녕하세요

&& (AND) 연산자

&& 연산자 기본형

두 개의 앰퍼샌드를 연달아 쓰면 AND 연산자 &&를 만들 수 있다.

result = a && b;

피연산자가 모두 참일 때 true를 반환한다. 그 외의 경우에는 false를 반환한다.

예시

console.log( true && true ); // true
console.log( true && false ); // false
console.log( false && true ); // false
console.log( false && false ); // false

&& 논리 연산자의 실제 사용 예시

let hour = 12;
let minuet = 30;

if (hour == 12 && minuet == 30) {
    console.log( '현재 시각은 12시 30분입니다.' );
}
if (1 && 0) {
    console.log('hello');
} // 작동하지 않음
// 0은 무조건 false이기 때문에 둘 다 truthy가 되어야만 true를 반환하는 && 연산자는 false를 반환한다.

첫번째 falsy한 값을 찾는 &&

|| (OR) 논리 연산자는 피연산자를 왼쪽부터 비교해가며 가장 먼저 등장하는 truthy한 값의 원래 값을 반환했다.

그런데 && (AND) 논리 연산자는 좌항이 true면 우항을 반환하고, 좌항이 false면 좌항을 반환한다.

&& 논리 연산자의 추가 기능 알고리즘
  1. 가장 왼쪽의 피연산자부터 싯작해 오른쪽으로 나아가며 피연산자를 평가한다.
  2. 각 피연산자는 불린형으로 변환된다. 변환된 값이 falsy한 값이 나오면 평가를 멈추고 해당 피연산자의 원래 값을 반환한다.
  3. 피연산자를 모두 평가했는데 모두 truthy한 값이 나오는 경우 마지막 피연산자를 반환한다.
console.log( 1 && 0 ); // 0
console.log( 1 && 5 ); // 5

console.log( null & 5 ); // null
console.log( 0 && "문자열" ); // 0
  • 추가적으로 && 연산자도 여러 개 중첩해서 사용할 수 있다.
  • &&와 ||가 동시에 사용되는 경우 &&가 우선순위가 높다.
console.log( 1 && 0 || 0 && "hello" ); // 0

// 위 식은 아래와 같다.
console.log( ( 1 && 0 ) || ( 0 && "hello" ));

console.log( 1 && 2 && 3 ); // 3

console.log( 1 && 2 && null && 3 ); // null;
// 1과 2 비교 : 1이 참이기 때문에 2 반환
// 2와 null 비교 : 2가 참이기 때문에 null 반환
// null과 3 비교 : null이 거짓이기 때문에 null 반환

&& 연산자를 if문 대체용으로 사용하지 말 것

&& 연산자는 피연산자를 왼쪽에서 오른쪽으로 차례대로 비교하면서 좌항이 참이면 우항을 반환한다는 특징 때문에 이를 if문을 대체해서 사용이 가능하다. 하지만 이처럼 사용하면 가독성이 떨어지기 때문에 권장하지 않는다.

// 부적절한 예시
let x = 1;

(x > 0) && console.log('0보다 큽니다!');

// 적절한 예시
let x = 1;

if (x > 0) {console.log('0보다 큽니다!')};

! (NOT) 연산자

논리 연산자 ! 는 앞에 붙이면 피연산자를 불린형으로 변환한 뒤 그 값을 반대로 뒤집는다.

console.log( !true ); // false
console.log( !0 ); // true

!!를 두 번 쓰면 '아니다의 아니다'가 된다. 즉 원상태다. 굳이 이것을 쓰는 이유는 ! 논리 연산자를 사용할 때 피연산자를 불린형으로 형 변환하는 특성을 사용하기 위해서이다. 즉 Boolean()이라는 형 변환 함수를 대체 가능하다.

console.log( !!'안녕하세요' ); // true
console.log( !!null ); // false

논리 연산자의 우선순위

! -> && -> || 순으로 높다.

정리

논리 연산자 반환 값
&& 좌항이 true면 우항 반환, false면 반대
|| 좌항이 true면 좌항 반환

이 부분은 암기의 영역인 것 같다. 며칠 지나면 또 헷갈린다.

올바른 학습방법인지는 모르겠으나, 나는 이렇게 이해하고자 한다.

  1. && 연산자는 if문을 대체할 수 있는 연산자이다. if문은 조건식이 참이면 우측으로 진행하는 성질이 있기 때문에 && 연산자 또한 좌항이 참이면 우측으로 진행한다고 이해된다.
    그리고 || 연산자는 truthy한 값을 찾아다닌다고 이해된다.
  1. && 연산자는 false를 찾아 다닌다. && 연산자는 피연산자가 여러개일 때 왼쪽부터 순서대로 비교하다가 false가 나오면 그 falsy한 값의 원래의 값을 반환하고 비교를 종료한다.
  1. || 연산자는 true를 찾아 다닌다. || 연산자는 피연산자가 여러개일 때 왼쪽부터 순서대로 비교하다가 true가 나오면 그 truth한 값의 원래 값을 반환하고 비교를 종료한다.

이게 왜 이렇게까지 안 외워지나 싶지만... 익숙해질 때까지는 연상법을 사용해야겠다...
'(오티)에 (엔에프)소나타를 타고...'

논리 연산자 전체식 반환 값
&& (and '그리고') 모든 피연산자가 truthy한 값이어야 전체식을 true로 반환
|| (or '또는') 피연산자 중 하나라도 truthy한 값이면 전체식을 true로 반환

연습문제

  1. 아래 코드의 결과는?
    console.log( null || 2 || undefined );
  2. 아래 코드의 결과는?
    alert( alert(1) || 2 || alert(3) );
  3. 아래 코드의 결과는?
    console.log( 1 && null && 2 );
  4. 아래 코드의 결과는?
    alert( alert(1) && alert(2) );
  5. 아래 코드의 결과는?
    console.log( null || 2 && 3 || 4 );
  6. age가 14세 이상, 90세 이하에 속하는지 확인하는 if문을 작성하시오.
  7. age가 14세 이상, 90세 이하에 속하지 않는지를 확인하는 if문을 작성하시오. (! 연산자를 사용한 답안과 사용하지 않은 답안 두 개를 작성하시오.)
  8. 아래 표현식에서 어떤 alert가 실행될 것인지 예측해보시오.
    if (-1 || 0) alert( 'first' );
    if (-1 && 0) alert( 'second' );
    if (null || -1 && 1) alert( 'third' );
  9. 로그인창 구현하기 문제는 원문에서 확인.

해답

  1. 2
    • &&는 좌항이 true면 우항 반환, ||는 좌항이 true면 좌항 반환.
    • 첫번째 비교인 null과 2의 비교에서 좌항이 false이기 때문에 우항 반환.
    • 그런데 우항이 2로 truthy한 값이기 때문에 2를 반환하고 비교 종료.
  2. alert창에 1, 2가 차례대로 출력된다.
    • alert 메서드는 값을 반환하지는 않는다. 즉 undefined 상태이다. undefined는 falsy한 값이다.
    • 일단 alert는 메서드이기 때문에 코드가 실행된다. 그리고 undefined와 2를 비교한다. undefined는 falsy한 값이기 때문에 || 연산자는 좌항이 true면 좌항을 반환하는데 반대의 경우기 때문에 우항을 검사한다. 그런데 우항이 숫자 2로 truthy한 값이기에 2를 반환하고 연산은 종료된다.
    • 즉 alert에서 1을 실행하라는 코드가 실행되고, () 소괄호 안에서 비교를 하다 2라는 값에서 비교 연산을 멈추고 2라는 값을 반환했기에 큰 코드블럭인 alert(2)까지 실행되어 실제 alert 창에는 1과 2가 연달아 출력된다. alert(3)의 평가는 이루어지지 않고 그 앞에서 멈췄다.
  3. null
    • 1과 null을 비교한다. || 연산자는 좌항이 true면 우항을 반환한다. 좌항이 숫자 1로 true이기 때문에 null을 반환한다. false가 나왔으므로 비교를 종료하고 null을 반환한다.
  4. alert창에 1, undefined가 차례대로 출력된다.
    • alert 메서드는 값이 없고 undefined이다. 일단 1항의 alert(1)의 코드가 실행되어 alert창에는 1이 출력된다.
    • 그리고 undefined는 falsy한 값이기에 false를 찾아 다니는 || 연산자는 비교를 멈춘다. 그리고 좌항의 값인 undefined를 반환한다.
    • 1항에서 이미 falsy한 값이 나왔기 때문에 우항은 진행되지 않고 비교도 진행되지 않는다.
  5. 3
    • 이 문제가 헷갈리는 이유는, ||, && 논리 연산자가 함께 쓰였을 때 논리 연산자의 우선순위가 존재하기 때문이다. 왼쪽에서부터 오른쪽으로 진행하는 것은 같은 연산자만 사용됐을 때의 이야기다.
    • 논리 연산자의 우선순위는 ! > && > || 순이다.
    • 즉 이 문제에선 2 && 3부터 비교한다. && 연산자는 falsy한 값을 찾는다. 둘 다 숫자로 truthy한 값이므로, && || 연산자 모두 둘 다 truthy하거나 falsy한 값이면 우항을 반환한다. 즉 여기선 3이 반환된다.
    • 그리고 다시 같은 연산자인 || 연산자만 남았으므로 좌측부터 순서대로 비교를 진행한다.
    • null || 3의 비교가 진행된다. null은 falsy한 값, 숫자 3은 truty한 값이므로 || 연산자는 truthy한 값을 찾는다는 목적을 달성했다. 따라서 3을 반환하고 뒤의 비교는 진행되지 않고 멈춘다.
  6. 해답
    • && 비교 연산자는 falsy한 값을 찾는 논리 연산자이다. 좌항과 우항에서 falsy한 값을 찾아야 하는데, 둘 다 truty한 값이면 true를 반환한다.
    • 크게는 if문이기 때문에 () 소괄호 안의 조건식이 true라면 if문은 {} 중괄호 안의 코드를 실행할 것이다. 그러나 피연산자 중 하나라도 falsy면 false를 반환하기 때문에 if문은 더 이상 진행하지 않는다.
    • 예를 들어 age에 9라는 값이 할당되었다면, 좌항은 false이지만 우항은 true가 된다. && 연산자는 모두 truty한 값이어야 전체식이 true가 된다. 따라서 하나라도 거짓이니 false를 반환하는 것이다.
  7. if (age >= 14 && age <= 90) {}
  8. 해답
  9. // ! 연산자 미사용 if (age < 14 || age > 90) {}

// ! 연산자 사용
if ( !(age >= 14 && age <= 90) ) {}


   - ! 연산자 미사용
     - age < 14 && age > 90이 아닌 이유는 age가 9라고 가정했을 때 14세보다 작으면서 90세 보다 크다는 두 가지 조건을 만족하는 것은 불가능 하기 때문에 둘 중 하나라도 만족하면 참이라고 보는 || 연산자를 사용한 것이다.
   - ! 연산자 사용
      - '14세 이상이면서 90세 이하인 age'를 먼저 && 연산자로 계산하고 괄호로 묶은 다음 ! 연산자를 넣어 값을 '아니다'의 개념을 추가해 뒤집으면 된다.

8. 'first', 'third' 두 개
   - 첫번째 표현식 : -1 || 0 의 비교에서 truthy한 값은 -1이다. -1은 true이므로 이 표현식은 실행된다. 참고로 숫자를 불린형으로 변환할 때 0 제외 나머지 수는 음수이든 양수이든 모두 truthy한 값이다.
   - 두번째 표현식 : -1 && 0 의 비교에서는 falsy한 값을 찾아야 하는데, 0이 falsy한 값이므로 0을 반환한다. 따라서 이 조건식은 false가 되므로 표현식이 실행되지 않는다.
   - 세번째 표현식 : null || -1 && 1 의 비교에서 &&이 ||보다 우선순위가 높기 때문에 -1 && 1부터 비교한다. &&은 falsy한 값을 찾는데, 둘다 truthy이므로 우항의 값을 반환한다. 따라서 null || 1의 비교가 진행되는데 ||은 truthy한 값을 찾으므로 1을 반환하고 이 조건식은 true가 되어 표현식이 실행된다. 
9. 로그인 창 구현하기
```javascript
let userName = prompt("사용자 이름을 입력해주세요.", '');

if (userName == 'Admin') {

  let pass = prompt('비밀번호:', '');

  if (pass == 'TheMaster') {
    alert( '환영합니다!' );
  } else if (pass == '' || pass == null) {
    alert( '취소되었습니다.' );
  } else {
    alert( '인증에 실패하였습니다.' );
  }

} else if (userName == '' || userName == null) {
  alert( '취소되었습니다.' );
} else {
  alert( "인증되지 않은 사용자입니다." );
}

댓글