자바스크립트에서만 제공하는 연산자
피연산자 : 연산자가 연산을 수행하는 대상을 말한다.
5 * 2
의 경우 왼쪽피연산자 : 5 / 오른쪽피연산자 : 2
단항(unary) : 피연산자를 하나만 받는 연산자를 말한다. 피연산자의 부호를 뒤집는 단항 마이너스 연산자 -
는 단항 연산자의 대표이다.
let x = 1;
x = -x;
alert( x ); // -1, 단항 마이너스 연산자는 부호를 뒤집는다.
이항(binary) : 두 개의 피연산자를 받는 연산자를 말한다. 마이너스 연산자-
는 아래와 같이 이항 연산자로 쓸 수도 있다.
let x = 1, y = 3;
alert( y - x ); // 2, 이항 마이너스 연산자는 뺄셈을 해준다.
위와 같이
1. 부호를 반전해주는 단항 마이너스 연산자
2. 뺄셈에 쓰이는 이항 마이너스 연산자(뺄셈 연산자)
는 기호는 같지만 수행하는 연산이 다르다. (두 연산을 구분하는 기준 : 피연산자의 개수)
덧셈 | 뺄셈 | 곱셈 | 나눗셈 | 나머지 | 거듭제곱 |
---|---|---|---|---|---|
+ | - | * | / | % | ** |
나머지 연산자는 사용한 표현식 a % b
는 a
를 b
로 나눈 후 그 나머지(remainder)를 정수로 반환한다.
alert( 5 % 2 ); // 5를 2로 나눈 나머지 = 1출력
alert( 8 % 3 ); // 8을 3으로 나눈 나머지 = 2를 출력
거듭제곱 연산자(exponentiation operator)를 사용한 a ** b
를 평가하면 a
를 b
번 곱한 값이 출력된다.
alert( 2 ** 2 ); // 4 (2 * 2)
alert( 2 ** 3 ); // 8 (2 * 2 * 2)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
거듭제곱 연산자는 정수가 아닌 숫자에 대해서도 동작한다.
alert( 4 ** (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
alert( 8 ** (1/3) ); // 2 (1/3 거듭제곱은 세제곱근)
+
는 대개 숫자를 더한 결과를 출력하지만 문자열을 입력하면 덧셈이 아닌 문자열을 병합(연결)한다.
let s = "my" + "string";
alert(s); // mystring
! 이항 연산자 +
를 사용할 때는 피연산자 중 하나가 문자열이면 다른 하나도 문자열로 변환된다
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
연산은 왼쪽에서 오른쪽으로 순차적으로 진행된다. 두 개의 숫자 뒤에 문자열이 오는 경우 숫자가 먼저 더해지고, 그 후 더해진 숫자와 문자열과의 병합이 일어난다.
alert(2 + 2 + '1' ); // '221'이 아니라 '41'이 출력
이처럼 이항 덧셈 연산자 +
는 문자열 연결과 변환 기능을 제공하는 한편, 다른 산술 연산자는 숫자형 피연산자만 다루고 피연산자가 숫자형이 아닌 경우 그 형을 숫자형으로 바꾸어 계산 후 출력한다.
아래는 뺄셈 -
과 나눗셈 /
연산자가 어떻게 문자형 피연산자를 다루는지를 보여준다.
alert( 6 - '2' ); // 4, '2'를 숫자로 바꾼 후 연산
alert( '6' / '2' ); // 3, 두 피연산자가 숫자로 바뀐 후 연산
덧셈 연산자 +
는 이항 연산자뿐만 아니라 단항 연산자로도 사용 가능하다.
숫자에 단항 덧셈 연산자를 붙이면 이 연산자는 변화가 없지만 피연산자가 숫자가 아닌 경우엔 숫자형으로의 변환이 일어난다.
// 숫자에는 아무런 변화가 없다.
let x = 1;
alert( +x ); // 1
let y = -2;
alert( +y ); // -2
// 숫자형이 아닌 피연산자는 숫자형으로 변환된다.
alert( +true ); // 1
alert( +"" ); // 0
단항 덧셈 연산자는 짧은 문법으로도 Number()
와 같은 역할을 한다.
개발을 하다 보면 문자열을 숫자로 변환해야 하는 경우가 자주 있다. HTML 폼(form) 필드에서 값을 가져왔는데 그 값이 문자형일 때와 같이 말이다. 실제로 폼에서 가지고 온 값은 대개 문자열 형태이다.
이항 덧셈 연산자를 사용하면 아래와 같이 값이 문자열로 변해서 연결된다.
let apples = "2";
let oranges = "3";
alert( apples + oranges ); // 23, 이항 덧셈 연산자는 문자열을 연결한다.
원하는 대로 값을 더해주려면 단항 덧셈 연산자를 이용해 피연산자를 숫자형으로 변화시키면 된다.
let apples = "2";
let oranges = "3";
// 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변형된다.
alert( +apples + +oranges ); // 5
// `Number()`를 사용해서 같은 동작을 하는 코드이다. (더 길다는걸 알 수 있다.)
alert( Number(apples) + Number(oranges) ); // 5
위 식은 단항 덧셈 연산자가 먼저 문자열을 숫자로 변환시키고 이항 덧셈 연산자가 그 결과들을 더해주고 있다.
! 이항 덧셈 연산자가 적용되기 전에 단항 덧셈 연산자가 먼저 적용되는 이유는 연산자 우선순위 때문이다.
하나의 표현식에 둘 이상의 연산자가 있는 경우 실행 순서는 연산자의 우선순위(precedence) 에 의해 결정된다.
연산자 우선순위는 1 + 2 * 2
라는 식이 있을 때 곱셈이 먼저 그 후 덧셈이 일어나는 것이다. 곱셈은 덧셈보다 더 높은 우선순위를 가진다.
! 정의한 연산자 우선순위를 바꾸고싶다면 괄호를 이용하면 된다.
자바스크립트는 다양한 연산자를 제공하고 연산자엔 우선순위가 매겨져 있다. 우선순위 숫자가 클수록 먼저 실행되며 순위가 같으면 왼쪽부터 오른쪽으로 연산이 수행된다.
아래는 우선순위 테이블(precedence table)의 일부이다.(순서기억x) 동일한 기호의 단항 연산자는 이항 연산자보다 우선순위가 더 높다는 것을 주의해야한다.
순위 | 연산자 이름 | 기호 |
---|---|---|
17 | 단항 덧셈 | + |
17 | 단항 부정 | - |
16 | 지수 | ** |
15 | 곱셈 | * |
15 | 나눗셈 | / |
13 | 덧셈 | + |
13 | 뺄셈 | - |
.. | .. | .. |
3 | 할당 | = |
'단항 덧셈 연산자’는 우선순위 17로, '이항 덧셈 연산자’ 우선순위(13)보다 높다는걸 알 수 있다. 그리하여 "+apples + +oranges"
에서 단항 덧셈 연산자가 이항 덧셈보다 먼저 수행된다.
할당할 때 쓰이는 연산자=
는 할당(assignment) 연산자라고 불리우며 우선순위는 3으로 낮은편이다.
x = 2 * 2 + 1
과 같은 표현식에서 계산이 먼저 이뤄지고 그 결과가 x에 할당되는 이유이다.
let x = 2 * 2 + 1;
alert( x ); // 5
=
는 연산자로 흥미로운 함축성을 내포하고 있다.
자바스크립트에서 대부분의 연산자들은 값을 반환한다. +
와 -
뿐만 아니라 =
역시 값을 반환한다.
x = value
를 호출하면 value가 x에 쓰여지고 이에 더해 value가 반환된다.
이 특징을 이용한 표현식이다.
let a = 1;
let b = 2;
let c = 3 - (a = b + 1);
alert( a ); // 3
alert( c ); // 0
위 예제에서 표현식 (a = b + 1)
은 a에 값을 할당하고, 그 값인 3을 반환한다. 그리고 반환 값은 이어지는 표현식에 사용된다.
다만 직접 코드를 작성할 땐 이런 방식을 사용하지 않는편이 좋다. 이런 트릭을 사용하면 코드가 명확하지 않을 뿐만 아니라 가독성도 떨어지기 때문이다.
할당 연산자는 아래와 같이 여러 개를 연결할 수도 있다.(체이닝)
let a, b, c;
a = b = c = 2 + 2;
alert( a ); // 4
alert( b ); // 4
alert( c ); // 4
이렇게 할당 연산자를 여러 개 연결한 경우 코드는 우측부터 진행된다. 먼저 가장 우측의 2 + 2가 계산되고, 그 결과가 좌측의 c, b, a에 순차적으로 할당된다. 모든 변수가 단일 값을 공유하게 되는 것이다.
가독성을 위해 되도록이면 연산자를 체이닝 하는것 보다 아래와 같이 줄을 나눠 코드를 작성하는 편이 좋다.
c = 2 + 2;
b = c;
a = c;
프로그램을 짜다 보면 변수에 연산자를 적용하고 그 결과를 같은 변수에 저장해야 하는 경우가 아래와 같이 종종 생긴다.
let n = 2;
n = n + 5;
n = n * 2;
이때 +=
와 *=
연산자를 사용하면 짧은 문법으로 동일한 연산을 수행할 수 있다.
let n = 2;
n += 5; // n은 7이 된다.(n = n + 5와 동일)
n *= 2; // n은 14가 된다.(n = n * 2와 동일)
alert( n ); // 14
이러한 ‘복합 할당’ 연산자는 산술 연산자와 비트 연산자에도 적용할 수 있다. /=
, -=
등의 연산자를 만들 수 있다.
복합 할당 연산자의 우선순위는 할당 연산자와 동일하다. ! 따라서 대부분 다른 연산자가 실행된 후에 복합 할당 연산자가 실행된다.
let n = 2;
n *= 3 + 5;
alert( n ); // 16 (*=의 우측이 먼저 실행, 위 식은 n *= 8과 동일)
숫자를 하나 늘리거나 줄이는 것은 자주 사용되는 연산이다.
let counter = 2;
counter++;
// counter = counter + 1과 동일하지만 식은 더 짧다는 것을 알 수 있다.
alert( counter ); // 3
let counter = 2;
counter--;
// counter = counter - 1과 동일하게 동작
alert( counter ); // 1
! 증가·감소 연산자는 변수에만 쓸 수 있다. 5++와 같이 값에 사용하면 에러가 발생한다.
후위형과 전위형은 피연산자인 counter를 1만큼 증가시켜 준다는 점에서 동일한 일을 하지만 두 형의 차이는 ++/--의 반환 값을 사용할 때 드러난다.
전위형은 증가·감소 후의 새로운 값을 반환하는 반면, 후위형은 증가·감소 전의 기존 값을 반환한다.
예시를 통해 차이점을 확인하자.
let counter = 1;
let a = ++counter; // (*)
alert(a); // 2
(*)로 표시한 줄의 전위형 ++counter는 counter를 증가시키고 새로운 값 2를 반환한다. (alert는 2를 표시)
let counter = 1;
let a = counter++; // (*) ++counter를 counter++로 바꿈
alert(a); // 1
(*)로 표시한 줄의 후위형 counter++는 counter를 증가시키긴 하지만, 증가 전의 기존 값을 반환한다. (alert는 1을 표시)
증가, 감소 연산자 내용정리
let counter = 0;
counter++;
++counter;
alert( counter ); // 2, 위 두 라인은 동일한 연산수행
let counter = 0;
alert( ++counter ); // 1
let counter = 0;
alert( counter++ ); // 0
다른 연산자 사이의 증가·감소 연산자
++/-- 연산자를 표현식 중간에 사용하는 것도 가능하다. 이때 증가·감소 연산자의 우선순위는 다른 대부분의 산술 연산자보다 높기 때문에 먼저 실행된다.
let counter = 1;
alert( 2 * ++counter ); // 4
위 예시를 아래와 비교
let counter = 1;
alert( 2 * counter++ ); // counter++는 '기존'값을 반환하기 때문에 2가 출력
이렇게 코드를 작성하는 게 기술적으로 문제가 있는 것은 아니지만 한 줄에서 여러 가지 일을 동시에 하고 있기 때문에 코드의 가독성이 떨어진다.코드를 읽을 때 눈을 ‘수직으로’ 빠르게 움직이다 보면 counter++와 같은 것을 놓치기 쉽다.
'코드 한 줄엔, 특정 동작 하나’에 관련된 내용만 작성하는 게 좋다.
let counter = 1;
alert( 2 * counter );
counter++;
비트 연산자(bitwise operator)는 인수를 32비트 정수로 변환하여 이진 연산을 수행한다.
비트 연산자 목록
비트 AND &
비트 OR |
비트 XOR ^
비트 NOT ~
왼쪽 시프트(LEFT SHIFT) <<
오른쪽 시프트(RIGHT SHIFT) >>
부호 없는 오른쪽 시프트(ZERO-FILL RIGHT SHIFT) >>>
쉼표 연산자(comma operator) ,
는 많이 사용하지 않는 연산자 중 하나이다. 코드를 짧게 쓰려고 할 때 가끔 사용된다.
쉼표 연산자 ,
는 여러 표현식을 코드 한 줄에서 실행될 수 있게 해준다. 이때 표현식 각각이 모두 실행되지만 마지막 표현식의 실행 결과만 출력된다.
let a = (1 + 2, 3 + 4);
alert( a ); // 7 (3 + 4의 결과)
위 예시에서 첫 번째 표현식 1 + 2
은 실행 되지만 그 결과는 버려지고 3 + 4
만 실행되어 a에 할당된다.
=
보다 더 낮아 위 예시의 괄호가 중요한 역할을 한다.a = 1 + 2, 3 + 4
에서 +
가 먼저 수행되어 a = 3, 7
이 된다.=
는 쉼표 연산자보다 우선순위가 높기 때문에 a = 3
이 먼저 실행되고 나머지7
은 무시된다. (a = 1 + 2), 3 + 4
이렇게 마지막 표현식을 제외한 모든 것을 버리는 연산자는 여러 동작을 하나의 줄에서 처리하려는 복잡한 구조에서 사용한다.
// 한 줄에서 세 개의 연산이 수행됨
for (a = 1, b = 3, c = a * b; a < 10; a++) {
...
}
쉼표 연산자의 사용 빈도는 높지 않지만(가독성이 떨어진다) 여러 자바스크립트 프레임워크에서 볼 수 있다.