[코어 자바스크립트] 2.8 기본 연산자와 수학

업데이트:
9 분 소요

출처 : 모던 JavaScript 튜토리얼


1. 용어 : ‘단항’, ‘이항’, ‘피연산자’

  • 피연산자(operand)는 연산자가 연산을 수행하는 대상이다. 4 * 5에는 왼쪽 피연산자 4와 오른쪽 피연산자 2, 총 두 개의 피연산자가 있다. ‘피연산자’는 ‘인수(argument)’라는 용어로 불리기도 한다.
  • 피연산자를 하나만 받는 연산자를 단항(unary) 연산자라 한다. 피연산자의 부호를 뒤집는 단항 마이너스 연산자 -는 단항 연산자의 대표적인 예이다.
let x = 1;

x = -x; // -는 단항 연산자
alert(x); // -1, 단항 연산자는 부호를 뒤집는다.
  • 두 개의 피연산자를 받는 연산자는 이항(binary) 연산자라 부른다. 마이너스 연산자는 이항 연산자로 쓸 수도 있다.
let x = 1, y = 3;
alert(y - x); // 2, 이항 마이너스 연산자는 뺄셈을 수행한다.
  • 부호를 반전해주는 단항 마이너스 연산자와 뺄셈에 쓰이는 이항 마이너스 연산자(뺄셈 연산자)는 기호는 같지만 수행하는 연산이 다르다. 두 연산을 구분하는 기준은 피연산자의 개수입니다.

2. 수학

자바스크립트에서 지원하는 수학 연산자

  • 덧셈 연산자 +
  • 뺄셈 연산자 -
  • 곱셈 연산자 *
  • 나눗셈 연산자 /
  • 나머지 연산자 %
  • 거듭제곱 연산자 **

나머지 연산자 %

  • 나머지 연산자(remainder operator)는 % 기호로 나타내지만, 비율을 나타내는 퍼센트와 관련이 없다.
  • 나머지 연산자를 사용한 표현식 a % bab로 나눈 후 그 나머지(remainer)를 정수로 반환한다.
alert( 7 % 3 ); // 5를 2로 나눈 후의 나머지인 1을 출력
alert( 10 % 4 ); // 8을 3으로 나눈 후의 나머지인 2를 출력

거듭제곱 연산자 **

  • 거듭제곱 연산자(exponentiation operator)를 사용한 a ** b를 평가하면 ab번 곱한 값이 반환된다.
alert( 2 ** 2 ); // 4  (2 * 2)
alert( 2 ** 3 ); // 8  (2 * 2 * 2)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
  • 거듭제곱 연산자는 정수가 아닌 숫자에 대해서도 동작한다. 1/2을 사용하면 제곱근을 구할 수 있다.
alert( 4 ** (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
alert( 8 ** (1/3) ); // 2 (1/3 거듭제곱은 세제곱근)

3. 이항 연산자 +와 문자열 연결

  • 덧셈 연산자 +는 대개 숫자를 더한 결과를 반환하는데, 이항 연산자 +의 피연산자로 문자열이 전달되면 덧셈 연산자는 덧셈이 아닌 문자열을 병합(연결)한다.
let s = "Hello," + " world!";
alert(s); // Hello, world!
  • 따라서 이항 연산자 +를 사용할 때는 피연산자 중 하나가 문자열이면 다른 하나도 문자열로 변환된다. 첫 번째 피연산자가 문자열인지, 두 번째 피연산자가 문자열인지는 중요하지 않다. 피연산자 중 어느 하나가 문자열이면 다른 하나도 문자열로 변환된다.
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
  • 하나의 표현식에서 +가 산술 연산자로도 사용되고, 이항 연산자로도 사용될 수도 있다. 연산은 왼쪽에서 오른쪽으로 순차적으로 진행되는데, 아래의 경우 두 개의 숫자 뒤에 문자열이 온다. 이 경우, 숫자가 먼저 더해지고, 그 후 더해진 숫자와 문자열과의 병합이 일어난다.
alert(2 + 2 + '1' ); // '221'이 아니라 '41'이 출력된다.
  • 아래는 뺄셈 -과 나눗셈 / 연산자는 피연산자로 숫자와 문자를 가질 때, 문자형 피연산자를 숫자로 바꾼 후 연산을 진행한다.
alert( 6 - '2' ); // 4, '2'를 숫자로 바꾼 후 연산이 진행된다.
alert( '6' / '2' ); // 3, 두 피연산자가 숫자로 바뀐 후 연산이 진행된다.

4. 단항 연산자 +와 숫자형으로의 변환

  • 덧셈 연산자 +는 이항 연산자 뿐만 아니라 단항 연산자로도 사용할 수 있다.
  • 숫자에 단항 덧셈 연산자를 붙이면 이 연산자는 아무런 동작도 하지 않는다. 그러나 피연산자가 숫자가 아닌 경우엔 숫자형으로 변환이 일어난다.
// 숫자에는 아무런 영향을 미치지 않는다.
let x = 1;
alert( +x ); // 1

let y = -2;
alert( +y ); // -2

// 숫자형이 아닌 피연산자는 숫자형으로 변한다.
alert( +true ); // 1
alert( +"" );   // 0
  • 단항 덧셈 연산자는 짧은 문법으로도 Number(...)와 동일한 일을 할 수 있게 해준다. 문자열을 숫자로 변환해야 할 때 간단하게 사용할 수 있다.
let apples = "2";
let oranges = "3";

alert( apples + oranges ); // 23, 이항 덧셈 연산자는 문자열을 연결한다.

// 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변한다.
alert( +apples + +oranges ); // 5

// `Number(...)`를 사용해서 같은 동작을 하는 코드를 작성할 수 있다.
// alert( Number(apples) + Number(oranges) ); // 5
  • 이항 덧셈 연산자가 적용되기 전에 단항 덧셈 연산자가 적용되는 이유는, 연산자 우선순위(precedence) 때문이다. 하나의 표현식에 둘 이상의 연산자가 있는 경우, 실행 순서는 연산자의 우선순위(precedence)에 의해 결정되는데, 동일한 기호의 단항 연산자는 이항 연산자보다 우선순위가 더 높다.

5. 할당 연산자

  • 무언가를 할당할때 쓰이는 =를 할당(assignment) 연산자라 한다. 우선순위는 3으로 아주 낮다.
  • x = 2 * 2 + 1과 같은 표현식에서 계산이 먼저 이뤄지고, 그 결과가 x에 할당되는 이유는 바로 할당 연산자의 우선순위가 낮기 때문이다.
let x = 2 * 2 + 1;

alert( x ); // 5

값을 반환하는 할당 연산자

  • =는 할당 연산자이기 함축성을 내포하고 있다. 자바스크립트에서 대부분의 연산자들을 값을 반환한다. x = value을 호출하면 valuex에 쓰여지고, 이에 더하여 value가 반환된다.
let a = 1;
let b = 2;

let c = 3 - (a = b + 1); // (a = b + 1)은 a에 값을 할당하고 3을 반환

alert( a ); // 3
alert( c ); // 0
  • 표현식 중간에 할당 연산자가 있을 경우, 반환 값은 이어지는 표현식의 연산에 사용된다.

할당 연사 체이닝

  • 할당 연산자는 여러 개를 연결할 수도 있다.
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;

6. 복합 할당 연산자

  • 변수에 연산자를 적용하고 그 결과를 같은 변수에 저장해야 하는 경우에 복합 할당 연산자를 사용한다.
let n = 2;
n += 5; // n = n + 5와 동일
n *= 2; // n = n * 2와 동일

alert( n ); // 14
  • 복합 할당 연산자는 산술 연산자와 비트 연산자에도 적용할 수 있다. /=, -= 등의 연산자를 만들 수 있다.
  • 복합 할당 연산자의 우선순위는 할당 연산자와 동일하다. 따라서 대부분 다른 연산자가 실행된 후에 복합 할당 연산자가 실행된다.
let n = 2;

n *= 3 + 5; // n *= 8과 동일

alert( n ); // 16

7. 증가·감소 연산자

  • 숫자를 하나 늘리거나 줄이는 것은 자주 사용되는데, 자바스크립트에서는 이런 연산을 해주는 연산자를 제공한다.
  • 증가(increment) 연산자 ++는 변수를 1 증가시킨다.
let counter = 2;
counter++;      // counter = counter + 1과 동일하게 동작
alert( counter ); // 3
  • 감소(decrement) 연산자 --는 변수를 1 감소시킨다.
let counter = 2;
counter--;      // counter = counter - 1과 동일하게 동작
alert( counter ); // 1

주의

  • 증가/감소 연산자는 변수에만 쓸 수 있다.
  • 5++와 같이 값에 사용하려고 하면 에러가 발생합니다.

후위형·전위형

  • ++-- 연산자는 변수 앞이나 뒤에 올 수 있다.
  • counter++와 같이 피연산자 뒤에 올 때는, ‘후위형(postfix form)‘이라고 부른다.
  • ++counter와 같이 피연산자 앞에 올 때는, ‘전위형(prefix form)‘이라고 부른다.
  • 후위형과 전위형은 피연산자인 counter를 1만큼 증가시켜 준다는 점에서 동일한 일을 하지만, 전위형은 증가/감소 후의 새로운 값을 반환하는 반면, 후위형은 증가/감소 전의 기존 값을 반환한다.
let counter = 1;
let a = ++counter; // 전위형 ++counter는 counter를 증가시키고 새로운 값 2를 반환

alert(a); // 2

let b = counter++; // 후위형 counter++는 증가 전의 값 2를 반환하고 counter를 증가시킴

alert(b); // 2
  • 반환 값을 사용하지 않는 경우라면, 전위형과 후위형엔 차이가 없습니다.
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 ); // ++counter가 먼저 실행되어 2가 리턴되고,최종적으로 4가 출력된다.
let counter = 1;
alert( 2 * counter++ ); // counter++는 '기존'값을 반환하기 때문에 2가 출력된다.
  • 한 줄에서 여러 가지 일을 동시에 하고 있기 때문에 코드의 가독성이 떨어진다. 따라서 ‘코드 한 줄엔, 특정 동작 하나’에 관련된 내용만 작성하는 게 좋다.
let counter = 1;
alert( 2 * counter );
counter++;

8. 비트 연산자

  • 비트 연산자(bitwise operator)는 인수를 32비트 정수로 변환하여 이진 연산을 수행한다.
  • 비트 조작 관련 연산자는 자바스크립트뿐만 아니라 대부분의 프로그래밍 언어에서 지원한다.
  • 비트 연산 시 쓰이는 연산자 목록
    • 비트 AND ( & )
    • 비트 OR ( | )
    • 비트 XOR ( ^ )
    • 비트 NOT ( ~ )
    • 왼쪽 시프트(LEFT SHIFT) ( << )
    • 오른쪽 시프트(RIGHT SHIFT) ( >> )
    • 부호 없는 오른쪽 시프트(ZERO-FILL RIGHT SHIFT) ( >>> )
  • 비트 연산자는 저수준(2진 표현)에서 숫자를 다뤄야 할 때 쓰이므로 흔하게 쓰이진 않지만, 암호를 다뤄야 할 땐 비트 연산자가 유용하다.

9. 쉼표 연산자

  • 쉼표 연산자(comma operator) ,는 좀처럼 보기 힘들고, 특이한 연산자이다. 코드를 짧게 쓰려는 의도로 가끔 사용된다.
  • 쉼표 연산자 ,는 여러 표현식을 코드 한 줄에서 평가할 수 있게 해준다. 이때 표현식 각각이 모두 평가되지만, 마지막 표현식의 평가 결과만 반환된다.
let a = (1 + 2, 3 + 4);

alert( a ); // 7 (3 + 4의 결과, 1 + 2의 결과는 버려진다.)
  • 쉼표 연산자의 연산자 우선순위는 할당 연산자 = 보다 더 낮다. 위의 코드에서 괄호가 없다면, a = 1 + 2, 3 + 4에서 +가 먼저 수행되어 a = 3, 7이 된다. 할당 연산자 =는 쉼표 언산자보다 우선순위가 높기 때문에 a = 3이 먼저 실행되고, 나머지(7)는 무시된다.
  • 마지막 표현식을 제외한 모든 것을 버리는 연삱
// 한 줄에서 세 개의 연산이 수행됨
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 ...
}
  • 쉼표 연산자를 사용한 트릭은 여러 자바스크립트 프레임워크에서 볼 수 있다. 쉼표 연산자는 코드 가독성에 도움이 되지 읺으므로 진짜 필요한 경우에만 사용하는 것이 좋다.

10. 과제

전위형과 후위형

아래 코드가 실행된 후, 변수 a, b, c, d엔 각각 어떤 값들이 저장될까요?

let a = 1, b = 1;

let c = ++a; // ?
let d = b++; // ?
  • 풀이
a = 2;
b = 2;
c = 2; 
d = 1;

할당 후 결과 예측하기

아래 코드가 실행되고 난 후, ax엔 각각 어떤 값이 저장될까요?

let a = 2;

let x = 1 + (a *= 2);
  • 풀이
a = 4;
x = 5;

형변환

아래 표현식들의 결과를 예측해 보세요.

"" + 1 + 0 // "10"
"" - 1 + 0 // -1
true + false // 1
6 / "3" // 2
"2" * "3" // 6
4 + 5 + "px" // "9px"
"$" + 4 + 5 // "$45"
"4" - 2 // 2
"4px" - 2 //
7 / 0 // NaN
"  -9  " + 5 // " -9 5"
"  -9  " - 5 // -14
null + 1 // 1
undefined + 1 // NaN (undefined는 숫자형으로 변환시 NaN이 된다.)
" \t \n" - 2 // -2 (" \t \n"는 숫자형으로 변환 시 길이가 0인 문자열로 취급)

덧셈 고치기

  • 아래 코드는 사용자에게 숫자 2개를 입력받은 다음 그 합을 보여줍니다. 그런데 의도한 대로 예시가 동작하지 않습니다. 프롬프트 창에 세팅한 기본값을 수정하지 않은 경우 덧셈의 결과는 12가 됩니다. 왜 그럴까요? 예시가 제대로 동작하도록 코드를 수정해 보세요. 결과는 3이 되어야 합니다.
let a = prompt("덧셈할 첫 번째 숫자를 입력해주세요.", 1);
let b = prompt("덧셈할 두 번째 숫자를 입력해주세요.", 2);

alert(a + b); // 12
  • 풀이
// 사용자에게 입력 받은 값이 문자열이기 때문에 12가 출력된다. 숫자로 변환해야 한다.

let a = +prompt("덧셈할 첫 번째 숫자를 입력해주세요.", 1);
let b = +prompt("덧셈할 두 번째 숫자를 입력해주세요.", 2);

alert(a + b); // 12