2.9 비교 연산자

컬러·2021년 1월 17일
0

JavaScript

목록 보기
10/27

자바스크립트에서 기본 수학 연산은 아래와 같은 문법을 사용해 표현할 수 있다.

  • 보다 큼, 작음: a > b, a < b
  • 보다 크거나, 작거나 같음: a >= b, a <= b
  • 같음(동등): a == b 등호 = 두 개 연달아 오는 것에 유의하자. a = b 와 같이 등호가 하나일 때는 할당을 의미한다.
  • 같지 않음(부동): 같지 않음을 나타내는 수학 기호 != 는 자바스크립트에선 a != b 로 나타낸다. 할당연산자 = 앞에 느낌표 ! 를 붙여서 표시한다.

불린형 반환

다른 연산자와 마찬가지로 비교 연산자 역시 값을 반환한다. 반환 값은 불린형이다.

  • true 가 반환되면, '긍정', '참', '사실'을 의미한다.
  • false 가 반환되면, '부정', '거짓', '사실'이 아님을 의미한다.

예)

alert( 2 > 1 ); // true
alert ( 2 == 1 ); // false
alert ( 2 != 1 ); // true

반환된 불린값은 다른 여타 값처럼 변수에 할당 할 수 있다.

let result = 5 > 4; // 비교 결과를 변수에 할당
alert(result); // true

문자열 비교

자바스크립트는 '사전'순으로 문자열을 비교한다. '사전편집(lexicographical)'순 이라고 불리기도 하는 이 기준을 적용하면 사전 뒤쪽의 문자열은 사전 앞쪽의 문자열보다 크다고 판단된다.

실제 단어를 사전에 실을 때 단어를 구성하는 문자 하나하나를 비교하여 등재 순서를 정하는 것과 같이 자바스크립트도 문자열을 구성하는 문자 하나하나를 비교해가며 문자열을 비교한다.

예)

alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true

문자열 비교 시 적용되는 알고리즘은 다음과 같다.

  1. 두 문자열의 첫 글자를 비교한다.
  2. 첫 번째 문자열의 첫 글자가 다른 문자열의 첫 글자보다 크면(작으면), 첫 번째 문자열이 두 번째 문자열보다 크다고(작다고) 결론 내고 비교를 종료
  3. 두 문자열의 첫 글자가 같으면 두 번째 글자를 같은 방식으로 비교
  4. 글자 간 비교가 끝날 때까지 이 과정을 반복
  5. 비교가 종료되었고 문자열의 길이도 같다면 두 문자열은 동일하다고 결론을 낸다. 비교가 종료되었지만 두 문자열의 길이가 다르면 길이가 긴 문자열이 더 크다고 결론 낸다.

예시의 'Z' > 'A' 는 위 알고리즘의 첫 번째 단꼐에서 비교 결과가 도출된다. 반면, 문자열 "Glow""Glee" 는 복수의 문자로 이루어진 문자열이기 때문에, 아래와 같은 순서로 문자열 비교가 이뤄진다.

  1. GG 와 같다.
  2. ll 과 같다.
  3. oe보다 크기 때문에 여기서 비교가 종료되고, o 가 있는 첫 번째 문자열 "Glow" 가 더 크다는 결론이 도출된다.

⚠️ 정확히는 사전순이 아니라 유니코드 순이다.

자바스크립트의 문자열 비교 알고리즘은 사전이나 전화번호부에서 사용되는 정렬 알고지름과 아주 유사하지만, 완전히 같진 않다.

차이점 중 하나는 자바스크립트는 대.소문자를 따진다는 것이다. 대문자 "A"와 소문자 "a" 를 비교햇을 때 소문자 "a" 가 더 크다. 자바스크립트 내부에서 사용되는 인코딩 표인 유니코드에선 소문자가 대문자보다 더 큰 인덱스를 갖기 때문이다.

다른 형을 가진 값 간의 비교

비교하려는 값의 자료형이 다르면 자바스크립트는 이 값들을 숫자형으로 바꾼다.

예)

alert( '2' > 1 ); // true, 문자열 '2'가 숫자 2로 변환된 후 비교가 진행
alert( '01' == 1 ); // true, 문자열 '01'이 숫자 1로 변환된 후 비교가 진행

불린값인 경우 true1, false0으로 변환된 후 비교가 이뤄진다.

예)

alert( true == 1 ); // true
alert( false == 0 ); // true

✅ 흥미로운 상황

같이 일어나지 않을 법한 두 상황이 동시에 일어나는 경우도 있다.

  • 동등 비교(==) 시 true를 반환함
  • 논리 평가 시 값 하나는 true, 다른 값 하나는 false를 반환함

예)

let a = 0;
alert( Boolean(a) ); // false

let b = "0";
alert( Boolean(b) ); // true

alert(a == b); // true!

두 값을 비교했을 때 참이 반환되는데, 값을 논리 평가한 후 비교하면 하나는 거짓이 반환된다는 점에 고개를 갸우뚱할 수도 있다. 자바스크립트의 관점에선 이런 결과가 아주 자연스럽다. 동등 비교 연산자 ==는 (예시에서 문자열 "0"을 숫자 0으로 변환시킨 것처럼) 피연산자를 숫자형으로 바꾸지만, 'Boolean'을 사용하면 명시적 변환에는 다른 규칙이 사용되기 때문이다.

일치 연산자

동등 연산자(equality operator) ==0false를 구별하지 못한다.

alert(0 == false); // true

피연산자가 빈 문자열일 때도 같은 문제가 발생

alert('' == flase); // true

이런 문제는 동등 연산자 ==가 형이 다른 피연산자를 비교할 때 피연산자를 숫자형으로 바꾸기 때문에 발생한다. 빈 문자열과 false는 숫자형으로 변환되면 0이 된다.

그렇다면 0false는 어떻게 구별할 수 있을까?

일치 연산자(strict equality operator) ===를 사용하면 형 변환 없이 값을 비교할 수 있다.

일치 연산자는 엄격한(strict) 동등 연산자이다. 자료형의 동등 여부까지 검사하기 때문에, 피연산자 ab의 형이 다를 경우 a === bfasle를 즉시 반환한다.

예)

alert(0 === false); // false, 피연산자의 형이 다르기 때문

일치 연산자 ===가 동등 연산자 ==의 엄격한 형태인 것처럼 "불일치"연산자 !==는 부동 연산자 !=의 엄격한 형태이다. 일치 연산자는 동등 연산자보다 한 글자 더 길긴 하지만 비교 결과가 명확하기 때문에 에러가 발생할 확률을 줄여준다.

null이나 undefined와 비교하기

null이나 undefined를 다른 값과 비교할 땐 예상치 않은 일들이 발생한다. 일단 몇 가지 규칙을 먼저 살펴본 후, 어떤 예상치 않은 일들이 일어나는지 구체적인 예시를 통해 살펴보자.

일치 연산자 ===를 사용하여 nullundefined를 비교

두 값의 자료형이 다르기 때문에 일치 비교 시 거짓이 반환된다.

alert( null === undefined ); // false

동등 연산자 ==를 사용하여 nullundefined를 비교

동등 연산자를 사용해 nullundefined를 비교하면 특별한 규칙이 적용돼 true가 반환된다. 동등 연산자는 nullundefined를 '각별한 커플'처럼 취급한다. 두 값은 자기들끼리 잘 어울리지만 다른 값들과는 잘 어울리지 못한다.

alert( null == undefined ); // true

산술 연산자나 기타 비교 연산자 < > <= >=를 사용하여 nullundefined 를 비교

nullundefined 는 숫자형으로 변환된다. null0, undefinedNaN로 변한다.

null vs 0

null과 0을 비교해 보자.

alert( null > 0); // 1. false
alert( null == 0 ); // 2. false
alert( null >= 0 ); // 3. true

위의 비교 결과는 논리에 맞지 않는다.

'3' 에서 null은 0보다 크거나 같다고 했기 때문에, '1' 이나 '2' 중 하나는 참이어야 하는데 둘 다 거짓을 반환하고 있다.

이는 동등 연산자 ==와 기타 비교 연산자 > < >= <=의 동작 방식이 다르기 때문이다.

'1'에서 null > 0이 거짓을, '3'에서 null >= 0이 참을 반환하는 이유는 (기타 비교 연산자의 동작 원리에 따라) null이 숫자형으로 변환돼 0이 되기 때문이다.

그런데 동등 연산자 ==는 피연산자가 undefined나 null일 때 형 변환을 하지 않는다. undefined와 null을 비교하는 경우에만 true를 반환하고, 그 이외의 경우(null이나 undefined를 다른 값과 비교할 때)는 무조건 false를 반환한다. 이런 이유 때문에 '2'는 거짓을 반환한다.

비교가 불가능한 undefined

undefined를 다른 값과 비교해서는 안된다.

alert( undefined > 0 ); // 1. false
alert( undefined < 0 ); // 2. false
alert( undefined == 0 ); // 3. false

위 예시의 결과를 보면 undefined는 0을 매우 싫어하는 것처럼 보인다. 항상 false를 반환하고 있다.

이런 결과는 아래와 같은 이유 때문에 발생한다.

  • '1'과' 2'에선 undefined가 NaN으로 변환되는데(숫자형으로의 변환), NaN이 피연산자인 경우 비교 연산자는 항상 false를 반환한다.
  • undefined는 null이나 undefined와 같고, 그 이외의 값과는 같지 않기 때문에 '3'은 false를 반환한다.

함정 피하기

위와 같은 에지 케이스를 왜 살펴보았을까? 이런 예외적인 경우를 꼭 기억해 놓고 있어야만 할까? 그렇지는 않다. 개발을 하다 보면 자연스레 이런 경우를 만나고 점차 익숙해지기 때문에 지금 당장 암기해야 할 필요는 없다. 하지만 아래와 같은 방법을 사용해 이런 예외 상황을 미리 예방할 수 있다는 점은 알아두자.

  • 일치 연산자 ===를 제외한 비교 연산자의 피연산자에 undefined나 null이 오지 않도록 특별히 주의하기
  • 또한, undefined나 null이 될 가능성이 있는 변수가 >= > < <=의 피연산자가 되지 않도록 주의하기
    • 만약 변수가 undefined나 null이 될 가능성이 있다고 판단되면, 이를 따로 처리하는 코드를 추가하기

✅ 과제


아래 표현식들의 결과를 예측해보자

5 > 4 // true
"apple" > "pineapple" 
"2" > "12" 
undefined == null
undefined === null
null == "\n0\n" // false
null === +"\n0\n"

해답

5 > 4true
"apple" > "pineapple"false
"2" > "12"true
undefined == nulltrue
undefined === nullfalse
null == "\n0\n"false
null === +"\n0\n"false
  1. 명백히 true
  2. 문자열의 비교는 사전순서가 기준이므로 false입니다. "a"는 "p"보다 작다.
  3. 두 피연산자는 문자열이므로, 사전순으로 비교가 이뤄집니다. 왼쪽 피연산자의 첫 번째 글자 "2"는 오른쪽 피연산자의 첫 번째 글자 "1"보다 크다.
  4. null과 undefined는 같다.
  5. 일치 연산자는 형도 체크합니다. 형이 다르면 false가 반환된다.
  6. (4)와 유사한 문제입니다. null은 오직 undefined와 같다.
  7. 형이 다르므로 false가 반환된다.

0개의 댓글