Skip to content

Latest commit

 

History

History
750 lines (478 loc) · 24.7 KB

08. Operator.md

File metadata and controls

750 lines (478 loc) · 24.7 KB

08. Operator

  • 연산자 표현식은 연산자와 피연산자로 이루어진 표현식이다.
  • 피연산자는 값으로 평가될 수 있는 표현식이어야 하며, 연산자 표현식 역시 값으로 평가될 수 있다.
  • 자바스크립트의 연산자들은 피연산자들의 개수에 따라 다음과 같이 나눌 수 있다.
    • 단항 연산자(unary operator): 피연산자가 1개인 연산자
    • 이항 연산자(binary operator): 피연산자가 2개인 연산자
    • 삼항 연산자(ternary operator): 피연산자가 3개인 연산자
  • 연산자가 피연사자의 값을 변경한다면 **부수 효과(side effect)**가 있다고 한다.

8.1 산술 연산자

**산술 연산자(arithmetic operator)**는 피연산자를 대상으로 수학적 계산을 하여 새로운 값을 반환하거나 피연산자의 값을 변경한다. 산술 연산이 불가능하다면 NaN을 반환한다.

이항 산술 연산자

자바스크립트의 모든 이항 산술 연산자는 부수 효과가 없다.

연산자 의미 설명
a + b 더하기 피연산자 ab를 더한 값을 반환한다.
a - b 빼기 피연산자 a에서 b를 뺀 값을 반환한다.
a * b 곱하기 피연산자 ab번 곱한 값을 반환한다.
a / b 나누기 피연산자 ab로 나눈 값을 반환한다.
a % b 나머지 구하기 피연산자 ab로 나누었을 때 나머지 값을 반환한다.
base ** exp 거듭제곱하기 피연산자 baseexp만큼 거듭제곱한다

단항 산술 연산자

연산자 의미 설명
+a 피연산자 anumber 타입이 아니면 number 타입으로 변환한 값을 반환한다.
피연산자의 부호를 바꾸지는 않는다.
-a 피연산자의 부호를 반전한다.
피연산자가 anumber 타입이 아니면 number 타입으로 변환한 값을 반환한다.
++a 혹은 a++ 증가 부수 효과가 있어 피연산자의 값을 1 증가시킨다.
--a 혹은 a-- 감소 부수 효과가 있어 피연산자의 값을 1 감소시킨다.

8.1.1 더하기 연산

  • 피연산자에 string 타입이 있다면 자바스크립트 엔진이 다른 피연산자를 string으로 변환하여 문자열 연결 연산(string concatenation)을 수행한다(8.8 문자열 연산자 참고).
  • 그렇지 않다면 피연산자들을 number로 변환하여 더하기 연산을 수행한다.
"10" + 1;	// "101"
10 + 1;		// 11
undefined + 1;	// NaN
null + 1;	// 0

8.1.2 빼기 연산

  • 피연산자가 number가 아니라면 number로 변환한 후 빼기 연산을 수행한다.
"10" - 2;	// 8
10 - 2;		// 8
10 - undefined;		// NaN
10 - null;		// 10

8.1.3 곱하기 연산

  • 피연산자가 number가 아니라면 number로 변환한 후 곱하기 연산을 수행한다.
"10" * 2;	// 20
10 * 2;		// 20
10 * undefined;		// NaN
10 * null;		// 0

8.1.4 나누기 연산

  • 피연산자가 number가 아니라면 number로 변환한 후 나누기 연산을 수행한다.
"10" / 2;	// 20
10 / 2;		// 5
10 / undefined;		// NaN
10 / null;		// Infinity
10 / -0;		// -Infinity

8.1.5 거듭제곱 연산

  • ES7에 도입되었다.
  • 피연산자가 number가 아니라면 number로 변환한 후 거듭제곱 연산을 수행한다.
"10" ** 2;	// 100
10 ** 2;	// 100
10 ** undefined;	// NaN
10 ** null;		// 1
10 ** -0;		// 1

8.1.6 단항 더하기, 빼기 연산

  • 피연산자가 number가 아니라면 number로 변환한 후 단항 더하기/빼기 연산을 수행한다.
  • 단항 빼기 연산은 피연산자의 부호를 바꾼 값을 반환한다.
+false;		// 0
-true;		// -1
-3;		// -3
+'hello';	// NaN

8.1.7 증감 연산자

  • 증가 연산자(increment opreator) ++는 피연산자의 값을 1만큼 증가 시킨다.
  • 감소 연산자(decrement opreator)는 --는 피연산자의 값을 1만큼 감소시킨다.
  • 증감 연산자는 피연산자 앞에 온다면 전위(prefix), 피연산자 뒤에 온다면 후위(postfix)이며 각각의 경우에 따라 연산이 다르다.
    • 전위 증감 연산자의 경우, 피연산자의 값을 증가/감소 시킨 후 다른 연산을 진행한다.
    • 후위 증감 연산자의 경우, 다른 연산을 수행한 후 피연산자의 값을 증가/감소시킨다.
/* 전위 연산자 */
let a = 1;
let b = a++;	// a의 값 1을 b에 할당한 후, a의 값을 1 증가시킨다.
// a: 2, b: 1	// 최종적으로 a의 값은 2, b의 값은 1이 된다.

/* 후위 연산자 */
let a = 1;
let b = ++a;	// a의 값을 1 증가시킨 후, a의 값 2를 b에 할당한다.
// a: 2, b: 2	// 최종적으로 a의 값은 2, b의 값은 2가 된다.

8.2 비교 연산자

**비교 연산자(comparsion opreator)**는 두 피연산자를 비교하여 그 결과를 boolean 타입의 값으로 반환한다. 부수 효과는 없다.

연산자 설명
== 두 피연산자가 같으면 true를 반환한다.
!= 두 피연산자가 같지 않으면 true를 반환한다.
=== 두 피연산자의 값과 타입이 모두 같으면 true를 반환한다.
!== 두 피연산자의 값 혹은 타입이 같지 않으면 true를 반환한다.
> 왼쪽 피연산자가 오른쪽 피연산자보다 크면 true를 반환한다.
< 왼쪽 피연산자가 오른쪽 피연산자보다 작으면 true를 반환한다.
>= 왼쪽 피연산자가 오른쪽 피연산자보다 크거나 같으면 true를 반환한다.
<= 왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같으면 true를 반환한다.

8.2.1 동등 연산자와 일치 연산자의 차이

  • **동등 비교(loose equality) 연산자 ==**와 **일치 비교(strict equality) 연산자 ===**는 피연산자가 같은 값으로 평가된다면 true를, 그렇지 않다면 false를 반환한다.
  • 이때 동등 비교 연산자는 느슨한 비교를 하고 일치 비교 연산자는 엄격한 비교를 한다.
  • 느슨한 비교에서 자바스크립트 엔진은 암묵적 타입 변환을 하여 피연산자의 타입을 일치시키고 같은 값으로 평가되었는지 비교한다.
  • 일치 비교는 두 피연산자의 타입과 값이 모두 일치할 경우 true를 반환한다. 달리 말하여 암묵적 타입 변환을 하지 않고 같은 값으로 평가되었는지 비교한다.
'1' == 1;		// true
'1' === 1;		// false

즉, =====의 가장 큰 차이는 ==는 암묵적 타입 변환을 하고 ===는 그러지 않는다는 것이다.

NaN의 동등과 일치 비교

  • NaN은 자신과 일치하지 않는 유일한 값이다.
NaN == NaN;		// false
NaN === NaN		// false
  • 어떤 숫자가 NaN인지 알려면 Number.isNaN 함수를 사용한다. Number.isNaNNaN인 경우에만 true를 반환한다.
Number.isNaN(NaN);		// true
Number.isNaN(1);		// false
Number.isNaN(1 + 'hello');	// true

undefinednull의 동등과 일치 비교

  • 예외적으로, 동등 비교 연산자 ==undefinednull을 형 변환하지 않는다. 피연산자 undefinednull은 자신이나 서로를 동등 비교하는 경우를 제하면 모든 경우에서 false를 반환한다.
/* 자신을 비교하는 경우 */
undefined == undefined;		// true
undefined === undefined;	// true
null == null;		// true
null === null;		// true

/* 서로를 비교하는 경우 */
undefined == null;		// true
undefined === null;		// false

/* 그 외의 모든 경우 */
null == 0;			// false
undefined == 0;		// false

0의 동등과 일치 비교

  • 자바스크립트에서 양의 0과 음의 0의 동등 비교와 일치 비교 결과는 모두 true이다.
0 == -0;		// true
0 === -0;		// true

8.2.2 타입이 다른 피연산자들의 대소 관계 비교

  • 두 피연산자가 모두 string이라면 문자열 비교 연산을 한다(8.8.2 문자열 비교 연산 참고).
  • 그렇지 않다면 피연산자들을 number로 변환하여 비교한다.
    • 피연산자가 number로 변환되지 않는다면, 즉 NaN으로 변환된다면 식은 무조건 false를 반환한다.
/* string to number comparsion */
"1" > 2;	// false
"3" > 1;	// true

/* comparing boolean, null, undefined, NaN */
true >= false;		// true
null >= 0;		// true
undefined >= 0;		// false
NaN >= 0;		// false
  • null0의 비교
null > 0;	// false
null < 0;	// false
null == 0;	// false: 동등 연산자는 undefined와 null의 경우 형 변환 안 함
null >= 0;	// true: 형 변환 하면 Number(null)은 0
null <= 0;	// true: 상동

8.3 삼항 연산자

  • **삼항 연산자(tenary opreator)**는 조건식의 평가 결과에 따라 반환할 값을 결정한다. 조건 연산자(conditional operator)라고도 한다.
  • 조건식이 boolean 타입이 아니면 boolean타입으로 암묵적 변환한다.
condition ? a : b;
  • conditiontrue로 평가되면 a를, false로 평가되면 b를 반환한다.

8.4 논리 연산자

**논리 연산자(logical operator)**는 피연산자를 논리 연산하여 불리언 값이나 피연산자 값 중 하나를 반환한다. 부수 효과는 없다.

연산자 설명
&& 논리 AND
`
! 논리 NOT
?? 널 병합

Short-circuit evaluation

단축 평가(short-circuit evaluation) 혹은 단락 평가는 표현식을 평가하는 도중 평가 결과가 확정된 경우 나머지 평가 과정을 생략하는 것을 말한다. 논리 연산에서는 표현식을 평가할 때 결과를 확정한 피연산자의 타입을 변환하지 않고 그대로 반환한다. 쉽게 판단하려면, 마지막으로 평가한 피연산자를 반환한다고 생각하면 된다.

8.4.1 논리 AND 연산

expr1 && expr2
  • 단락 평가(short-circuit evaluation)를 사용: 논리 연산자 표현식은 왼쪽에서 오른쪽으로 평가된다. 이때 왼쪽 연산자가 Falsy로 평가되면 오른쪽 피연산자는 평가하지 않고 표현식을 Falsy로 평가한다(왼쪽 피연산자를 반환한다).
  • 논리 AND 연산은 피연산자 중 하나를 반환한다. 다음과 같이 일반화할 수 있다.
    • 피연산자 중 하나가 Falsy라면 해당 피연산자를 반환한다.
    • 그렇지 않다면, 오른쪽 피연산자를 반환한다.
"BLUE" && "YELLOW";	// "YELLOW": 두 연산자가 모두 Truthy, 오른쪽 피연산자인 "YELLOW" 반환
"BLUE" && false;	// false: 한 연산자만 Falsy, 해당 피연산자인 false를 반환한다.
"BLUE" && null;		// null: 상동
null && undefined;	// null: 두 연산자가 모두 Falsy, 오른쪽 피연산자인 undefined 반환

8.4.2 논리 OR 연산

expr1 || expr2
  • 단락 평가(short-circuit evaluation)를 사용: 논리 연산자 표현식은 왼쪽에서 오른쪽으로 평가된다. 이때 왼쪽 피연산자가 Truthy로 평가되면, 오른쪽 피연산자는 평가하지 않고 표현식을 Truthy로 평가한다(왼쪽 피연산자를 반환한다).
  • 논리 OR 연산은 피연산자 중 하나를 반환한다. 다음과 같이 일반화할 수 있다.
    • 왼쪽 피연산자가 Falsy이면 오른쪽 피연산자를 반환한다.
    • 그렇지 않다면, 왼쪽 피연산자를 반환한다.
"BLUE" || "YELLOW";		// "BLUE"
"BLUE" || false;		// "BLUE"
0 || undefined;			// undefined

8.4.3 논리 NOT 연산

!expr
  • 논리 NOT 연산은 피연산자가 Falsy라면 false를, Truthy라면 true를 반환한다.
let b1 = !"BLUE";		// false
let b2 = !false;		// true
  • !을 두 번 사용하면 피연산자의 boolean 값으로 평가한 결과를 얻을 수 있다.
let b1 = !!'BLUE';	// true
let b2 = !!'false';	// true

'false'string 타입이고 빈 문자열이 아니므로 Truthy이고 불리언 문맥에서 true로 평가된다. 따라서 !'false'false, !!'false'true가 된다.

단축 평가와 객체의 프로퍼티 접근하기

변수의 값이 객체라고 기대하고 프로퍼티를 접근하려 할 때, 변수의 값이 null이나 undefinednullish value라면 TypeError가 발생한다.

/* 변수의 값이 undefined인 경우 */
let a;
console.log(a.foo);		// TypeError: Cannot read properties of undefined (reading 'foo')

/* 변수의 값이 null인 경우 */
let b;
console.log(b.foo);		// TypeError: Cannot read properties of undefined (reading 'foo')

/* 변수가 빈 객체인 경우 */
let c;
console.log(c.foo);		// undefined

변수의 값이 객체라면, 그것이 빈 객체({})여도 할당되지 않은 프로퍼티를 접근할 때 TypeError를 발생시키지 않고 undefined를 반환한다. 따라서 객체의 프로퍼티에 접근하기 전에 변수가 객체인지 확인해야만 한다.

논리 AND 연산자 &&와 단축 평가하기

let a;
let foo = a && a.foo;
console.log(foo);	// undefined

처음 코드에서 a의 값이 undefined이므로 a.fooTypeError를 발생시켰다. 그러나 왼쪽 피연산자인 a는 Falsy로 평가되고 단축 평가에 따라 오른쪽 피연산자는 평가하지 않고 오른쪽 피연산자 a의 값인 null이이 논리 연산의 결과가 된다.

ES11의 옵셔널 체이닝 연산자 ?.로 개선된 문법을 사용할 수 있다. 8.4.4 옵셔널 체이닝을 참고한다.

논리 OR 연산자 ||와 단축 평가하기

const getFoo = (obj) => obj.foo;
getFoo();	// TypeError: Cannot read properties of undefined (reading 'foo')

함수에 인수를 전달하지 않으면 매개변수에는 undefined가 할당된다. 여기서 인수 없이 getFoo()를 호출하여 obj에는 undefined가 할당되었고, 따라서 obj.foo로 nullish value에 프로퍼티 접근을 시도하여 TypeError가 발생했다.

이 경우 임의의 초기값을 가지도록 설정해줄 수 있다.

const getFoo = (obj) => {
    obj = obj || {}
    return obj.foo;
};
getFoo();		// undefined

왼쪽 피연산자인 obj가 Falsy로 평가되므로 단축 평가에 따라 오른쪽 피연산자 {}이 이 논리 연산자 표현식의 값이 된다. obj{}이 새롭게 할당되었고 obj.foo로 선언되지 않은 프로퍼티에 접근해도 undefined를 반환하므로 TypeError를 발생시키지 않는다.

ES11의 null 병합 연산자 ??로 개선된 문법을 사용할 수 있다. 8.4.5 널 병합 연산을 참고한다.

8.4.4 옵셔널 체이닝

ES11에 도입된 옵셔널 체이닝(Optional Chaining) 연산자 ?.는 왼쪽 항의 피연산자가 nullish라면 undefined를 반환하고 그렇지 않다면 오른쪽 항의 프로퍼티 참조를 수행한다.

  • 문제 상황: nullish value에 프로퍼티 접근하면 TypeError 발생
let a;
let foo = a.foo;	// // TypeError: Cannot read properties of undefined (reading 'foo')
  • 기존 논리 AND 연산자 && 사용하여 해결
let a;
let foo = a && a.foo;
console.log(foo);	// undefined
  • ES11의 옵셔널 체이닝 ?. 사용하여 개선
let a;
let foo = a?.foo;
console.log(foo);	// undefined

Optional Chaining 참고

8.4.5 널 병합 연산

ES11에 도입된 널 병합(nullish coalescing) 연산자 ??는 왼쪽 항의 피연산자가 nullish라면 오른쪽 항의 피연산자를 반환하고 그렇지 않다면 왼쪽 항의 피연산자를 반환한다.

  • 문제 상황: 원하는 값이라면 그대로 할당하고 원하는 값이 아니면 재할당하고 싶음
let name;
if (name === undefined)
    name = 'unknown';
console.log(name);	// 'unknown'
  • 기존의 논리 OR 연산자 || 사용하여 개선
let name;
name = name || 'unknown';
console.log(name);	// 'unknown'

하지만 첫번째 라인에서 name''로 초기화되었다고 해보자. 프로그래머는 nullish가 아니라면 모두 유효한 값이라고 생각하여 name에 그대로 ''가 재할당되기를 기대할 수 있다.

let name = '';
name = name || 'unknown';	// ''는 nullish가 아니므로 false를 그대로 재할당하기를 기대함
console.log(name);	// 'unknown'

그러나 ''는 Falsy이므로, ||의 단축 평가에 따라 name에는 'unknown'이 담기게 된다. nullish가 Falsy에 속하므로 ||로는 프로그래머가 기대하는 작업을 할 수 없다.

  • ES11의 널 병합 연산 ?? 사용
let name = '';
name = name ?? 'unknown';
console.log(name);		// ''

''는 nullish가 아니므로 프로그래머의 기대처럼 name에 재할당된다.

Nullish Coalescing 참고

널 병합 연산자 ??와 논리 OR 연산자 ||의 차이

false || 'TEDDY';	// 'TEDDY'
false ?? 'TEDDY';	// false
연산자 왼쪽 피연산자가 반환
?? nullish value(null, undefined)인 경우 오른쪽 피연산자를 반환한다.
` `
  • false는 nullish value가 아니므로, 위 경우의 ?? 식에서는 왼쪽 피연산자 false가 반환된다.
  • false는 Falsy value이므로, 위 경우의 || 식에서는 오른쪽 피연산자 'TEDDY'가 반환된다.

널 병합 연산자 ??와 옵셔널 체이닝 연산자 ?.의 차이

??는 명확하게 nullundefined를 처리할 때 유용하다. ?.null이나 undefined일 수 있는 객체의 프로퍼티에 접근할 때 TypeError가 발생하지 않도록 한다.

8.5 비트 연산자(수정중)

연산자 설명
& 비트 AND
` `
^ 비트 XOR
~ 비트 NOT
<< 비트 왼쪽 시프트
>> 비트 오른쪽 시프트
>>> 비트 부호 없는 오른쪽 시프트

8.6 할당 연산자

**할당 연산자(assignment operator)**는 오른쪽 항에 있는 피연산자의 평가 결과를 왼쪽 항에 있는 변수에 할당한다. 따라서 부수 효과가 있다.

연산자 설명
x = y x = y
x += y x += y
x -= y x -= y
x *= y x = x * y
x /= y x = x / y
x %= y x = x % y
x **= y x = x ** y
x <<= y x = x << y
x >>= y x = x >> y
x >>>= y x = x >>> y
x &= y x = x & y
x ^= y x = x ^ y
`x = y`
x &&= y x && (x = y)
`x
x ??= y x ?? (x = y)

chaining

  • 할당문은 값으로 평가되는 표현식인 문이므로 할당된 값으로 평가된다.
var x;
console.log(x = 10);	// 10
  • 따라서 할당문은 표현식으로서 다른 변수에 할당할 수도 있다. 이것을 체이닝(chaining)이라고 한다.
const a = b = 10;
console.log(a);		// 10
  • 할당식을 여러 개 체이닝하는 경우 각각의 할당식은 오른쪽에서 왼쪽으로 차례대로 평가한다.
const a = b = c;
// const a = ( b = c ); 와 같음.

8.8 문자열 연산자

8.8.1 문자열 연결 연산

  • +은 피연산자에 string 타입이 있으면 string concatenation을 수행한다.
'HELLO ' + 'WORLD';	// "HELLO WORLD"
let str = 'HELLO';
str += 'WORLD';		// str은 "HELLO WORLD"

8.8.2 문자열 비교 연산

  • <, >, <=, >= 연산은 피연산자가 모두 string이면 문자열 비교 연산을 한다.
'a' > 'b';		// false
'a' > '3';		// true
'abc' > 'abd';	// false

8.9 쉼표 연산자

쉼표 연산자 ,는 왼쪽에서 오른쪽으로 피연산자를 평가한 후, 가장 마지막 피연산자의 평가 결과를 반환한다.

let x = (2, 3);
console.log(x);		// 3

let a, b, c;

a = 1, b = 2, c = 3;	// 3

8.10 그룹 연산자

그룹 연산자는 피연산자를 ()로 감싸 자신의 피연산자인 표현식을 가장 먼저 평가한다. 그룹 연산자는 우선순위가 가장 높으므로 연산자의 우선순위를 조절할 수 있다.

9 * 1 + 3;		// 12
9 * (1 + 3);	// 36

8.11 기타 단항 연산자

8.11.1 delete 연산자

delete 연산자는 객체의 프로퍼티를 삭제하므로 부수 효과가 있다.

delete object.property;
delete object[propertyKey];
delete objectName[index];
연산자 반환 설명
delete boolean 객체의 프로퍼티를 삭제한다.
성공적으로 삭제했다면 true를, 그렇지 않다면 false를 반환한다.
  • 다만, 존재하지 않는 프로퍼티를 삭제하려 할 때에도 true를 반환한다.
let o = { name: 'umi', age: 6 };
console.log(delete o.name);		// true
  • 전역 객체의 경우 var로 선언한 전역 변수를 제외한 모든 프로퍼티를 삭제할 수 있다.

8.11.2 typeof 연산자

typeof 연산자는 피연산자의 데이터 타입을 문자열로 반환한다.

typeof operand
typeof (operand)
연산자 반환 설명
typeof string 혹은 undefined 피연산자의 타입을 나타내는 문자열(number, string, boolean, undefined, object, function, symbol, bigint)을 반환한다.
typeof null;		// object

선언하지 않은 식별자의 타입

typeof에 선언하지 않은 식별자를 피연산자로 전달하면 ReferenceError를 일으키지 않고 undefined를 반환한다.

typeof x;		// undefined

8.11.3 void 연산자(수정중)

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/void

void (expression)
void expression
연산자 반환 설명
void undefined 피연산자를 평가한다.

8.11 관계 연산자

8.11.1 in 연산자

프로퍼티객체에 존재하는지 여부를 반환한다.

프로퍼티 in 객체
연산자 반환 설명
in boolean 프로퍼티객체에 존재하면 true를, 그렇지 않다면 false를 반환한다.
const COLORS = [ 'BLUE', 'YELLOW' ];
'BLUE' in COLORS;	// true

let user = { name: 'lana' };
'lana' in user;		// true

8.11.2 instanceof 연산자

객체가 생성자 함수와 연결된 인스턴스인지 여부를 반환한다.

객체 instanceof 생성자함수
연산자 반환 설명
instanceof boolean 객체생성자함수와 연결된 인스턴스라면 true를, 그렇지 않다면 false를 반환한다.
new Date() instanceof Date;		// true
new Date() instanceof Object;	// true