[자바스크립트 완벽가이드] 4장_표현식과 연산자 (2)

유동균·2023년 3월 7일
0
post-thumbnail

7. 연산자 개요

연산자는 산술 표현식, 비교 표현식, 논리 표현식, 할당 표현식 등에 사용된다.

대부분의 연산자는 부호로 표현되지만 deleteinstanceof같은 키워드 연산자도 있다.
키워드 연산자도 부호로 표현된 것과 마찬가지로 일반적인 연산자이다.

아래의 표는

  • 연산자 우선순위로 배치 되었다. 아래로 갈수록 우선순위가 높다.
    비어있는 셀로 구분한 것은 연산자 우선순위가 다르다는 뜻이다.

  • A로 표시한 열은 연산자 결합성(Associativity)을 나타낸다.
    L은 왼쪽에서 오른쪽으로, R은 오른쪽에서 왼쪽을 뜻한다.

  • N으로 표시한 열은 피연산자의 개수이다.

  • 타입이라고 표시한 열은 피연산자와 결과(화살표 뒤)의 타입을 뜻한다.

lval(lvalue 왼쪽 값) : 할당 표현식의 왼쪽에 나타날 수 있는 표현식 (변수, 객체 프로퍼티, 배열 요소)

연산자동작AN타입
++전위(후위) 증가R1lval → num
--전위(후위) 감소R1lval → num
-숫자의 부호 변경R1num → num
+숫자로 변환R1any → num
~비트를 반대로R1int → int
!불 값을 반대로R1bool → bool
delete프로퍼티 제거R1lval → bool
typeof피연산자의 타입을 반환R1any → str
voidundefined 값을 반환R1any → undef
**지수R2num, num → num
*, /, %곱셈, 나눗셈, 나머지L2num, num → num
+, -덧셈, 뺄셈L2num, num → num
+문자열 병합L2str, str → str
<<왼쪽 시프트L2int, int → int
>>부호 붙은 오른쪽 시프트L2int, int → int
>>>>0으로 채우는 오른쪽 시프트L2int, int → int
<, <=, >, >=숫자로 비교L2num, num → bool
<, <=, >, >=문자열을 알파벳 순서로 비교L2str, str → bool
instanceof객체 클래스 체크L2obj, func → bool
in프로퍼티가 존재하는지 체크L2any, obj → bool
==동등성 체크L2any, any → bool
!=비동등성 체크L2any, any → bool
===일치 체크L2any, any → bool
!==불일치 체크L2any, any → bool
&비트 ANDL2int, int → int
^비트 XORL2int, int → int
|비트 ORL2int, int → int
&&논리 ANDL2any, any → any
||논리 ORL2any, any → any
??첫 번째로 정의된 피연산자 선택L2any, any → any
?:두 번째로 정의된 피연산자 선택R3bool, any, any → any
=변수나 프로퍼티에 할당R2lval, any → any
**=, *=, /=, %=,+=, -=, &=, ^=, |=,<<=, >>=, >>>=연산 후 할당R2lval, any → any
,첫 번째 피연산자를 버리고 두 번째를 반환L2any, any → any

7.1 피연산자 개수

연산자는 예상하는 피연산자 개수(항, arity)를 기준으로 분류할 수 있다.

  • 3항 연산자
    ?:는 조건 연산자라고도 부르며 표현식 세 개를 하나로 바꾼다.

  • 2항 연산자
    곱셈 연산자 *처럼 자바스크립트 연산자 대부분은 표현식 두 개를 조합해 하나로 만드는 2항 연산자이다.
    즉, 피연산자 두 개를 받는다는 뜻.

  • 단항 연산자
    -x 표현식의 - 연산자는 피연산자 x의 부호를 바꾸는 단항 연산자이다.
    즉, 표현식 하나를 다른 표현식으로 변환하는 단항 연산자.

7.2 피연산자와 결과 타입

값의 타입에 관계없이 동작하는 연산자도 있지만, 대부분은 피연산자가 특정 타입일 것으로 간주하며 특정 타입의 값을 반환한다.

자바스크립트 연산자는 필요에 따라 피연산자의 타입을 변환한다.
곱셈 연산자 *는 피연산자가 숫자를 예상하지만, 표현식 "3" * "5"는 유효한 표현식이다.
자바스크립트가 피연산자를 숫자로 변환할 수 있기 때문이다.
이 표현식의 값은 문자열 "15"가 아닌 숫자 15이다.

피연산자의 타입에 따라 다르게 동작하는 연산자도 있다.
+ 연산자는 피연산자가 숫자이면 더하고, 문자열이면 병합한다.
마찬가지로 < 같은 비교 연산자는 피연산자 타입에 따라 숫자 순서로도, 알파벳 순서러도 비교할 수 있다.

7.3 연산자와 부수 효과

2 * 3 같은 단순한 표현식을 평가하는 것은 프로그램의 상테에 어떤 영향도 미치지 않으며 이후의 연산은 이 평가에 영향받지 않는다.
하지만 일부 표현식에는 이후의 평가 결과에 영향을 미치는 부수 효과(side effect)가 있다.

변수나 프로퍼티에 값을 할당하면 해당 변수나 프로퍼티를 사용하는 모든 표현식에 영향일 미친다.
증가 연산자 ++, 감소 연산자 -- 역시 부수 효과가 있다.
프로퍼티를 삭제하는 것은 해당 프로퍼티에 undefined를 할당하는 것과 비슷하다.

다른 자바스크립트 연산자에는 부수 효과가 없다.
함수나 생성자 바디에 부수 효과가 있는 연산자를 사용한다면 해당 함수 호출이나 객체 생성 표현식에도 부수 효과가 있다.

7.4 연산자 우선 순위

연산자 우선순위는 동작 순서를 결정한다. 우선순위가 높은 연산자는 우선순위가 낮은 연산자보다 먼저 실행 된다.

w = x + y * z;

곱셈 연산자가 덧셈 연산자보다 우선순위가 높으므로 곱셈이 덧셈보다 먼저 이뤄진다.
또한 할당 연산자의 우선 순위가 가장 낮으므로 할당은 오른쪽의 동작이 모두 끝난 후에 이뤄진다.

괄호를 사용해서 연산자 우선순위를 덮어 쓸 수 있다.

// 덧셈을 첫 번째로 수행
w = (x + y) * z;

어떠한 연산자들보다 프로퍼티 접근과 호출 표현식의 우선순위가 더 높다.

// my에 functions라는 프로퍼티가 있고 그 값은 함수의 배열
// 번호가 x인 함수를 호출하면서 인자 y를 전달하고 반환되는 값의 타입을 구한다.
typeof my.functions[x](y)

typeof 연산자는 우선순위가 가장 높은 연산자 중 하나이지만, typeof 동작은 프로퍼티 접근, 배열 인덱스, 함수 호출 다음에 이뤄진다.

자바스크립트에 새 연산자가 추가될 때 항상 우선순위 규칙을 따르는 것은 아니다.
?? 연산자는 ||, &&보다 우선순위가 낮지만 사실 이들 사이의 상대적 우선순위는 아직 정의되지 않았으며,
ES2020은 ??||&&와 함께 사용할 때 명시적으로 괄호를 사용할 것을 요구한다.
**와 단항 부정(-) 연산자의 우선순위도 명확히 정의되지 않았으므로 마찬가지이다.

7.5 연산자 결합성

연산자 표의 A열은 연산자의 결합성을 나타낸다.
L은 왼쪽에서 오른쪽으로 연산하는 좌결합성, R은 오른쪽에서 왼쪽으로 연산하는 우결합성을 나타낸다.
연산자의 결합성은 우선순위가 같은 동작을 수행할 때의 순서이다.

// 좌결합성
w = x - y - z;

// 위 표현식의 동등 표현식
w = ((x - y) - z);
// 우결합성
y = a ** b ** c;
x = ~-y;
w = x = y = z;
q = a?b:c?d:e?f:g;

// 위 표현식의 동등 표현식
y = (a ** (b ** c));
x = ~(-y);
w = (x = (y = z));
q = a?b:(c?d:(e?f:g));

7.6 평가 순서

연산자 우선순위와 연관성은 복잡한 표현식에서 어떤 순서로 동작이 수행되는지는 지정하지만,
하위 표현식이 평가되는 순서는 지정하지 않는다.

자바스크립트는 항상 표현식을 왼쪽에서 오른쪽으로 평가한다.
w = x + y * z 표현식에서는 하위 표현식 w를 첫 번째로 평가하고, 그 다음 x, y, z를 순서대로 평가한다.
그런 다음 y와 z의 값을 곱하고, x의 값을 더한 다음 표현식 w에서 지정한 변수나 프로퍼티에 할당한다.
표현식에 괄호를 추가해서 곱셈, 덧셈, 할당 순서를 바꿀 수 있지만 왼쪽에서 오른쪽으로 진행하는 평가 순서를 바꿀 수는 없다.

평가 순서는 평가하는 표현식에 다른 표현식의 값에 영향을 미치는 부수 효과가 있을 때만 의미가 있다.
표현식 x가 표현식 z에서 사용하는 변수를 증가시킨다면, z보다 x를 먼저 평가한다.

8. 산술 표현식

기본 산술 연산자에는 ** 지수, * 곱셈, / 나눗셈, % 나머지, + 덧셈, - 뺄셈이 있다.
덧셈을 제외한 나머지 연산자는 피연산자를 평가해서 필요하다면 숫자로 변환한 다음 제곱, 곱, 몫, 나머지, 차이를 계산한다.
숫자가 아니며 숫자로도 변환할 수 없는 피연산자는 NaN 값으로 변환된다.

** 연산자는 *, /, %보다 우선순위가 높으며, 세 연산자는 +, -보다 우선순위가 높다.
다른 연산자와 달리 **는 오른쪽에서 왼쪽으로 동작하므로 2 ** 2 ** 34 ** 3이 아니라 2 ** 8과 같다.
-3 ** 2 같은 표현식에는 태생적 모호함이 있다.
단항 마이너스와 지수의 우선순위 관계에 따라, 이 표현식은 (-3) ** 2이 될 수도 있고 (-3 ** 2)가 될 수도 있다.
(자바스크립트는 괄호를 생략하면 문법 에러를 일으킨다는 해결법을 채택했다.)

/ 연산자는 첫 번째 피연산자를 두 번째 피연산자로 나눈다.
자바스크립트에서는 모든 숫자가 부동 소수점이므로 나눗셈의 결과 역시 항상 부동 소수점이다. 5/22가 아니라 2.5이다.
0으로 나누면 양의 무한대 또는 음의 무한대이고, 00으로 나누면 NaN이다.

% 연산자는 첫 번째 피연산자를 두 번째 피연산자로 나눈 나머지이다.
결과의 부호는 첫 번째 피연산자를 따른다.

나머지 연산자는 일반적으로 정수 피연산자를 받긴 하지만, 부동 소수점 값도 사용할 수 있다.

8.1 + 연산자

2항 연산자 +는 숫자 피연산자는 더하고 문자열 피연산자는 병합한다.

1 + 2							// 3;
"hello" + " " + "there"			// "hello there"
"1" + "2"						// "12"

피연산자가 모두 숫자거나 모두 문자열이라면 + 연산자가 어떻게 동작할지 명백히 알 수 있다.
하지만 두 타입이 일치하지 않는다면 타입 변환이 필요하고, 어느쪽에 우선권이 있는지 정해야한다.
+ 연산자의 변환 규칙은 문자열 병합에 우선순위가 있다.
피연산자 중 하나가 문자열, 또는 문자열로 변환할 수 있는 객체라면 다른 피연산자를 문자열로 변환하고 둘을 병합한다.
두 피연산자가 모두 문자열로 판단할 수 없을 때에만 덧셈을 수행한다.

엄밀히말해 + 연산자는 아래와 같이 동작한다.

  • 피연산자 중 하나가 객체라면 객체에서 기본 값으로 변환하는 알고리즘을 사용해 기본 값으로 변환한다.
    Date 객체는 toString() 메서드를 호출하며 다른 객체는 valueOf() 메서드를 호출한다.
    하지만 대부분의 객체에서 valueOf() 메서드는 유용하지 않으므로 대개 toString()이 호출된다.
  • 객체에서 기본 값으로 변환하고 난 뒤 피연산자 중 하나가 문자열이면 다른 하나를 문자열로 변환한 다음 병합한다.
  • 둘 다 문자열이 아니라면 숫자(또는 NaN)로 변환한 후 더한다.
1 + 2			// 3;					덧셈
"1" + "2"		// "12";				병합
"1" + 2			// "12";				숫자를 문자열로 변환한 후 병합
1 + {}			// "1[object Object]";	객체를 문자열로 변환한 후 병합
true + true		// 2;					불 값을 숫자로 변환한 후 덧셈
2 + null		// 2;					null을 0으로 변환한 후 덧셈
2 + undefined	// NaN;					undefined를 NaN으로 변환한 후 덧셈

마지막으로 중요한 점은, + 연산자의 피연산자가 문자열과 숫자일 때 그 연관성은 명확하지 않다는 것이다.
즉, 동작 순서에 따라 결과가 달라질 수 있다는 뜻이다.

1 + 2 + " blind mice"		// "3 blind mice"
1 + (2 + " blind mice")		// "12 blind mice"

첫 번째 행에는 괄호가 없고 + 연산자의 결합성은 왼쪽에서 오른쪽이므로 먼저 두 숫자를 더한 다음 그 합에 문자열을 병합한다.

두 번째 행에서는 괄호 때문에 순서가 달라졌다.
따라서 숫자 2와 문자열을 병합해서 문자열을 얻고, 다시 숫자 1과 새 문자열을 병합해 결과를 얻는다.

8.2 단항 산술 연산자

단항 연산자는 피연산자 하나의 값을 바꿔 새 값을 얻는다.
자바스크립트에서 단항 연산자는 모두 우선순위가 높으며 전부 오른쪽에서 왼쪽으로 연산을 수행한다.

8.2.1 단항 플러스 +

단항 플러스 연산자는 피연산자를 숫자(또는 NaN)로 변환한 값을 반환한다.
이미 숫자인 피연산자에 적용한다면 아무일도 하지 않는다.
BigInt 값은 일반적인 숫자로 변환할 수 없으므로 단항 플러스 연산자를 사용할 수 없다.

8.2.2 단항 마이너스 -

-를 단항 연산자로 사용하면 필요한 경우 피연산자를 숫자로 변환한 다음 부호를 바꾼다.

8.2.3 증가 ++

++ 연산자는 피연산자에 1을 더하며, 그 피연산자는 반드시 왼쪽 값(변수, 객체 프로퍼티, 배열 요소)이어야 한다.
이 연산자는 피연산자를 숫자로 변환하고 1을 더한다음 증가된 값을 다시 피연산자에 할당한다.

++ 연산자의 반환 값은 피연산자와 연산자의 위치 관계에 따라 다르다.
피연산자의 앞에 있을 때 이를 전위 증가 연산자라 부른다. 이 연산자는 피연산자의 값에 1을 더한 다음, 그 값으로 평가된다.
피연산자의 뒤에 있을 때 이를 후위 증가 연산자라 부른다. 이 연산자는 피연산자의 값에 1을 더하긴 하지만, 더하기 전의 값으로 평가된다.

let i = 1, j = ++i;		// i와 j는 모두 2이다.
let n = 1, m = n++;		// n은 2이고 m은 1이다.

표현식 x++가 항상 x = x + 1과 같은 것은 아니다. ++ 연산자는 절대 문자열 병합을 수행하지 않는다.
이 연산자는 항상 피연산자를 숫자로 변환해서 1을 더한다.
x가 문자열 "1"이라면 ++x는 숫자 2지만, x + 1은 문자열 "11"이다.

자바스크립트의 자동 세미콜론 삽입 기능 때문에 후위 증가 연산자와 피연산자 사이에서 줄을 바꿀 수는 없다.

8.2.3 감소 --

-- 연산자는 피연산자가 왼쪽 값이라고 예상한다. 이 연산자는 피연산자의 값을 숫자로 변환한 뒤 1을 빼고 다시 피연산자에 할당한다.
++ 연산자와 마찬가지로 -- 연산자의 반환 값은 피연산자와의 위치 관계에 따라 다르다.
피연산자가 앞에 있을 때는 피연산자의 값에서 1을 빼고 그 값을 반환하고,
피연산자가 뒤에 있을 때는 피연산자의 값에서 1을 빼는 것은 마찬가지지만 '1을 빼기 전'의 값을 반환한다.

8.3 비트 연산자

비트 연산자는 숫자의 이진 표현의 비트를 대상으로 저수준 조작을 수행한다.
비트 연산자가 전통적인 의미의 산술 연산을 수행하지는 않지만, 숫자 피연산자를 받고 숫자 값을 반환하므로 산술 연산자로 분류한다.

비트 연산자 중 네 가지는 피연산자의 개별 비트를 대상으로, 마치 각 비트가 불 값인 것처럼(1은 true, 0은 false) 불 연산을 수행한다.
나머지 세 비트 연산자는 비트를 왼쪽이나 오른쪽으로 이동(shift)한다.
이들 연산자는 자바스크립트 프로그래밍에서 널리 쓰이는 연산자가 아니다.

비트 연산자는 피연산자에 정수 값을 예상하며, 이 값이 64비트 부동 소수점 값이 아니라 32비트 정수인 것처럼 동작한다.
이들 연산자는 필요하다면 피연산자를 숫자로 변환하고, 그 숫자 값에서 소수 부분과 32번째 이후의 비트를 모두 버려서 32비트 정수로 강제 변환한다.
시프트 연산자의 오른쪽 피연산자는 0이상 31 이하여야 한다.
시프트 연산자는 이 피연산자를 부호 없은 32비트 정수로 변환한 다음 다섯 번째를 넘어가는 비트를 모두 버려서 적절한 범위의 숫자로 만든다.

NaN, Infinity, -Infinity에 시프트 연산자를 적용한 결과는 모두 0이다.

>>>를 제외한 비트 연산자는 일반적인 숫자와 BigInt 피연산자에 모두 사용할 수 있다.

8.3.1 비트 AND (&)

& 연산자는 피연산자인 정수의 각 비트에 불 AND 연산을 수행한다.
두 피연산자에 모두 대응하는 비트가 있어야 결과 비트도 채워진다.
0x1234 & 0x00FF0x0034로 평가된다.

8.3.2 비트 OR (|)

| 연산자는 피연산자인 정수의 각 비트에 불 OR 연산을 수행한다.
두 피연산자 중 하나라도 대응하는 비트가 있으면 결과 비트가 채워진다.
0x1234 | 0x00FF0x12FF로 평가된다.

8.3.3 비트 XOR (^)

^ 연산자는 피연산자인 정수의 각 비트에 불 XOR 연산을 수행한다.
XOR은 첫 번째 피연산자가 true이거나 두 번째 피연산자가 true인 것은 가능하지만 둘 다 true인 것은 안된다는 의미.
두 피연산자 중 한쪽에만 대응하는 비트가 있어야 결과 비트가 채워진다.
0xFF00 ^ 0xF0F00x0FF0로 평가된다.

8.3.4 비트 NOT (~)

~ 연산자는 정수 피연산자 하나만 받는 단항 연산자이다.
이 연산자는 피연산자의 비트를 모두 거꾸로 뒤집는다.
자바스크립트에서 부호 붙은 정수를 표현하는 방법 때문에, 값에 ~ 연산자를 적용한 결과는 피연산자의 부호를 바꾸고 1을 뺀 것과 동등하다.
~0x0F0xFFFFFF0(-16)과 같다.

8.3.5 왼쪽 시프트 (<<)

<< 연산자는 첫 번째 피연산자의 비트를 모두 두 번째 피연산자 값만큼 왼쪽으로 이동한다.
따라서 두 번째 피연산자으 ㅣ값은 0 이상 31 이하이다.
a << 1에서 a의 첫 번째 비트는 결과의 두 번째 비트가 되고, a의 두 번째 비트는 결과의 세 번째 비트가 되는 식이다.
가장 왼쪽에 있던 비트는 버리고, 새로 생긴 마지막 자리에는 0을 쓴다.
값을 왼쪽 한 자리 이동하면 2를 곱하는 것과 같고, 두 자리 이동하면 4를 곱하는 것과 같다.
7 << 228이다.

8.3.6 부호 붙은 오른쪽 시프트 (>>)

>> 연산자는 첫 번째 피연산자의 모든 비트를 두 번째 피연산자의 숫자(0 이상 31 이하 정수)만큼 오른쪽으로 이동한다.
오른쪽으로 밀려난 비트는 버리고, 첫 번째 피연산자에 채워지는 비트는 피연산자의 부호를 유지할 수 있도록 부호 비트로 채운다.
첫 번째 피연산자가 양수면 결과는 이동하는 만큼 0으로 채우고, 첫 번째 피연산자가 음수면 결과는 이동하는 만큼 1로 채운다.
양수 값을 오른쪽으로 한 자리 이동하는 것은 2로 나누고 나머지를 버리는 것과 같고,
오른쪽으로 두 자리 이동하는 것은 4로 나누고 나머지를 버리는 것과 같다.
7 >> 13이지만, -7 >> 1-4이다.

8.3.7 0으로 채우는 오른쪽 시프트 (>>>)

>>> 연산자는 >> 연산자와 비슷하지만 첫 번째 피연산자의 부호와 관계없이 항상 0으로 채운다는 점이 다르다.
이 연산자는 부호 붙은 32비트 값을 부호 없는 정수처럼 취급할 때 유용하다.
-1 >> 4-1, -1 >>> 40x0FFFFFF이다.
이 연산자는 BigInt 값과 함께 사용할 수 없는 유일한 비트 연산자이다.
BigInt 타입은 32비트 정수가 부호 비트를 바꿔서 음수를 표현하는 것과는 다른 방식으로 음수를 표현하기 때문이다.
이 연산자는 2의 보수 표현을 사용하는 타입에만 사용할 수 있다.

9. 관계 표현식

관계 연산자는 두 값 사이의 관계를 나타내며, 관계에 따라 false 또는 true를 반환한다.
관계 표현식은 항상 불 값으로 평가되며, 이 값은 보통 if, while, for 같은 제어문에서 사용된다.

9.1 일치와 불일치 연산자

===== 연산자는 두 값이 같은지 체크하며, 서로 다른 기준을 사용한다.
숫자, 문자열, 객체 등 어떤 피연산자든 받을 수 있으며, 피연산자가 같을 때는 true를 반환하고 같지 않을 때는 false를 반환한다.

=== 연산자를 일치 연산자라 부르며, 엄격한 정의에 따라 두 피연산자가 '완전히' 일치하는지 체크한다.
== 연산자는 동등 연산자라 부르며, 값을 비교할 때 타입 변환을 허용하므로 두 피연산자가 '같다고 볼 수 있는지' 체크한다.

!=!== 연산자는 정반대이다.
!= 비동등 연산자는 두 피연산자가 == 비교에 따라 동등하다 볼 수 있으면 false를 반환하고, 그렇지 않으면 true를 반환한다.
!=== 불일치 연산자는 두 피연산자가 === 비교에 따라 완전히 일치할 때 false를 반환하고, 그렇지 않으면 true를 반환한다.

자바스크립트 객체는 값이 아닌 참조로 비교한다.
객체는 자기 자신과 같지만, 다른 어떤 객체와도 같지 않다.
별개의 두 객체가 프로퍼티 숫자도 같고, 이름과 값까지 같다 하더라도 둘은 다른 객체이다.
마찬가지로, 두 배열이 같은 요소를 같은 순서로 포함하고 있어도 서로 다른 배열이다.

9.1.1 일치

일치 연산자=== 는 먼저 피연산자를 평가한 다음, 두 값을 아래와 같이 비교하되 타입 변환은 수행하지 않는다.

  • 두 값이 다른 타입이면 값은 같은 값이 아니다.
  • 두 값이 모두 null이거나 모두 undefined이면 같은 값이다.
  • 두 값이 모두 불 값 true거나 불 값 false이면 같은 값이다.
  • 두 값 중 하나라도 NaN이면 같은 값이 아니다.
    NaN은 자기 자신을 포함해 어떤 값과도 같지 않다. 값 xNaN인지 체크하려면 x !== x 또는 isNaN() 사용
  • 두 값이 모두 숫자이고 값이 같다면 같은 값이다.
    하나가 0이고 다른 하나가 -0이면 역시 같은 값
  • 두 값이 모두 문자열이고 같은 위치에 정확히 같은 16비트 값을 포함한다면 같은 값이다.
    문자열의 길이나 내용이 다르다면 같은 값이 아니다.
    두 문자열의 의미가 같고 눈으로 보기에 같더라도 내부 표현인 16비트 값은 서로 다를 수 있다.
  • 두 값이 같은 객체, 배열, 함수를 참조한다면 같은 값이다.
    다른 객체를 참조한다면 같은 값이 아니다. 설령 두 객체의 프로퍼티가 일치한다해도 같은 값이 아니다.

9.1.2 동등성과 타입 변환

동등 연산자 ==는 일치 연산자에 비해 덜 엄격하다.
두 피연산자가 같은 타입이 아니라면 이 연산자는 타입을 변환한 뒤 아래와 같이 비교를 시도한다.

  • 두 값이 같은 타입이라면 위의 설명대로 일치하는지 체크한다.
    두 값이 일치한다면 같은 값이고 같지 않다면 같은 값이 아니다.
  • 두 값이 같은 타입이 아니더라도 == 연산자는 두 값이 같다고 판단할 수 있다.
    동등 연산자는 아래의 규칙과 타입 변환을 통해 같은 값인지 체크한다.
    • 하나가 null이고 다른 하나가 undefined이면 같은 값이다.
    • 하나가 숫자이고 다른 하나가 문자열이라면 문자열을 숫자로 변환하고, 변환된 값을 사용해 다시 비교한다.
    • 값 중 하나가 ture면 1로 변환한 후 다시 비교한다.
      값 중 하나가 false이면 0으로 변환한 후 다시 비교한다.
    • 값 중 하나가 객체이고 다른 값이 숫자나 문자열이면 알고리즘에 따라 객체를 기본 값으로 변환한 후 다시 비교한다.
      객체는 toString() 메서드 또는 valueOf() 메서드를 통해 기본 값으로 변환된다.
      코어 자바스크립트의 내장 클래스는 toString() 변환보다 먼저 valueOf() 변환을 시도하는데,
      Date 클래스는 예외이며 이 클래스는 toString() 변환을 사용한다.
    • 그 외에는 모두 다른 값이다.
"1" == true		// true

이 표현식은 true로 평가된다. 표현식 양쪽은 완전히 다른 값으로 보이지만 같다고 볼 수 있다는 뜻이다.
불 값 true를 먼저 숫자로 변환한 후 다시 비교한다.
다음에는 문자열 "1"을 숫자 1로 변환한다. 두 값이 같은 값이므로 true를 반환한다.

9.2 비교 연산자

비교 연산자는 아래와 같이 피연산자의 순서(숫자 또는 알파벳)를 비교한다.

미만 (<)
< 연산자는 첫 번째 피연산자가 두 번째 피연산자보다 작으면 true를, 그렇지 않으면 false를 반환한다.

초과 (>)
< 연산자는 첫 번째 피연산자가 두 번째 피연산자보다 크면 true를, 그렇지 않으면 false를 반환한다.

이하 (<=)
<= 연산자는 첫 번째 피연산자가 두 번째 피연산자보다 작거나 같으면 true를, 그렇지 않으면 false를 반환한다.

이상 (>=)
>= 연산자는 첫 번째 피연산자가 두 번째 피연산자보다 크거나 같으면 true를, 그렇지 않으면 false를 반환한다.

이들 비교 연산자는 피연산자의 타입을 가리지 않는다.
하지만 비교는 숫자와 문자열에 대해서만 가능하므로, 피연산자는 숫자나 문자열로 변환된다.

비교와 변환은 아래와 같이 이뤄진다.

  • 피연산자 중 하나가 객체로 평가되면 그 객체를 기본 값으로 변환한다.
    valueOf() 메서드가 기본 값을 반환하면 그 값을 사용하고, 그렇지 않으면 toString() 메서드의 반환 값을 사용한다.
  • 객체를 기본 값으로 변환한 후, 두 피연산자가 모두 문자열이라면 두 문자열을 알파벳 순서로 비교한다.
    여기서 '알파벳 순서'란 문자열을 구성하는 16비트 유니코드 값으 숫자 순서이다.
  • 객체를 기본 값으로 변환한 결과, 문자열이 아닌 피연산자가 있다면 두 피연산자를 숫자로 변환한 후 비교한다.
    0-0은 같은 값으로 간주한다.
    Infinity는 자기 자신을 제외한 어떤 값보다 크고 -Infinity는 자기 자신을 제외한 어떤 값보다 작다.
    두 피연산자 중 하나라도 NaN이거나 NaN으로 변환된다면 비교 연산자는 항상 false를 반환한다.
    산술 연산자는 BigInt 값과 일반적인 숫자를 섞어 쓸 수 없지만, 비교 연산자는 숫자와 BigInt의 비교를 허용한다.

자바스크립트 문자열은 16비트 정수의 연속이며 문자열 비교는 사실 두 문자열을 구성하는 값의 비교이다.
인코딩 숫자의 순서는 유니코드에서 정의하며 특정 언어나 지역에서 상식으로 받아들이는 순서와 다를 수 있다.
문자열 비교는 대소문자를 구분하며, ASCII 대문자는 모두 ASCOO 소문자보다 작다.

문자열 비교 알고리즘이 필요할 때 String.localeCompare() 메서드를 사용할 수 있다.
이 메서드는 해당 지역의 상식에 맞는 알파벳 순서를 판단 기준에 포함한다.
대소문자를 가리지 않고 비교한다면 String.toLowerCase()String.toUpperCase()를 사용해 전부 소문자 또는 대문자로 통일하여 비교할 수 있다.

+ 연산자와 비교 연산자는 모두 피연산자가 숫자냐 문자열이냐에 따라 다르게 동작한다.
+는 문자열을 선호한다. 즉, 피연산자 중 하나라도 문자열이라면 병합하려 한다.
반대로 비교 연산자는 숫자를 선호하며, 두 피연산자가 모두 문자열일 때만 문자열 비교를 수행한다.

1 + 2			// 3;		덧셈
"1" + "2"		// "12";	병합
"1" + 2			// "12";	2는 "2"로 변환
11 < 3			// false;	숫자 비교
"11" < "3"		// true;	문자열 비교
"11" < 3		// falase;	숫자 비교. "11"은 11로 변환
"one" < 3		// falase;	숫자 비교. "one"은 NaN으로 변환

<=>= 연산자는 두 값이 '같은 지' 판단할 때 일치 연산자의 기준을 적용하지 않는다.
<=는 '보다 크지 않다'로 >=는 '보다 작지 않다'로 정의되어있다.
한 가지 예외는 피연산자 중 하나가 NaN이거나 NaN으로 변환되는 경우인데, 이때는 네 가지 비교 연산자가 모두 false를 반환한다.

9.3 in 연산자

in 연산자는 왼쪽 피연산자가 문자열, 심벌, 문자열로 변환될 수 있는 값이라고 예상하고, 오른쪽 피연산자는 객체라고 예상한다.
이 연산자는 왼쪽 피연산자가 오른쪽 객체의 프로퍼티 이름일 경우 true를 반환한다.

let point = {x: 1, y: 1};	// 객체 정의
"x" in point				// true;	객체에 "x"라는 프로퍼티가 있다.
"z" in point				// false;	객체에 "z"라는 프로퍼티가 없다.
"toString" in point			// true;	객체는 toString 메서드를 상속한다.

0개의 댓글