JavaScript 연산자, 수학

David Kim·2022년 8월 1일
1

JavaScript Basic

목록 보기
4/6
post-thumbnail

단항, 이항, 피연산자

연산자를 알아보기 전에 알아두어야 할 용어입니다.

  • 피연산자(operand)는 연산자가 연산을 수행하는 대상입니다. 예를 들어 수식 5 \* 2에는 왼쪽 피연산자 5와 오른쪽 피연산자 2, 총 두 개의 피연산자가 있습니다. 피연산자는 "인수(argument)"라는 용어로 불리기도 합니다.

  • 피연산자를 하나만 받는 연산자는 단항(unary) 연산자라고 부릅니다. 피연산자의 부호를 뒤집는 단항 마이너스 연산자 -는 단항 연산자의 대표적인 예입니다.

    let x = 1;
    x = -x;
    console.log(x) // -1, 단항 마이너스 연산자는 부호를 뒤집습니다.​​
  • 두 개의 피연산자를 받는 연산자는 이항(binary) 연산자라고 부릅니다. 마이너스 연산자는 아래와 같이 이항 연산자로 사용할 수도 있습니다.

    let x = 1, y = 3;
    console.log( y - x ); // 2, 이항 마이너스 연산자는 뺄셈을 해줍니다.​​

    위와 같이 부호를 반전해주는 단항 마이너스 연산자와 뺄셈에 쓰이는 이항 마이너스 연산자는 기호는 같지만 수행하는 연산이 다릅니다. 두 연산을 구분하는 기준은 피연산자의 개수입니다.

연산자의 종류

자바스크립트에서 지원하는 수학 연산자는 다음과 같습니다.

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

덧셈 연산자 ~ 나눗셈 연산자는 일반적인 사칙연산과 같기 때문에 별도의 설명 없이 넘어가고 나머지 연산자와 거듭제곱 연산자에 대해 설명하겠습니다.

나머지 연산자 %

나머지 연산자(remainder operator)는 % 기호로 나타내지만, 비율을 나타내는 퍼센트와 관련이 없습니다.

나머지 연산자를 사용한 표현식 a % bab로 나눈 후 그 나머지를 정수로 반환합니다.

console.log(5 % 2); // 1
console.log(8 % 3); // 2

거듭제곱 연산자 **

거듭제곱 연산자(exponentiation operator)를 사용한 표현식 a ** b를 연산하면 ab번 곱한 값이 반환됩니다.

console.log(2 ** 2); // 4
console.log(2 ** 3); // 8
console.log(2 ** 4); // 16

거듭제곱 연산자는 정수가 아닌 숫자에 대해서도 동작합니다. 1/2을 사용하면 제곱근을 구할 수 있습니다.

console.log(4 ** (1 / 2)); // 2
console.log(8 ** (1 / 3)); // 2

이항연산자 '+' 문자열 연결

덧셈 연산자 +는 대개 숫자를 더한 결과를 반환합니다.

그런데 이항 연산자 +의 피연산자로 문자열이 전달되면 덧셈 연산자는 덧셈이 아닌 문자열을 병합합니다.

console.log('1' + 2); // "12"
console.log(2 + '1'); // "21"

첫 번째 피연산자가 문자열인지, 두 번째 피연산자가 문자열인지는 중요하지 않습니다. 피연산자 중 어느 하나가 문자열이면 다른 하나도 문자열로 변환됩니다.

console.log(2 + 2 + '1'); // "41"

연산은 왼쪽에서 오른쪽으로 순차적으로 진행되기 때문에 이런 결과가 나오게됩니다. 두 개의 숫자 뒤에 문자열이 오는 경우, 숫자가 먼저 더해지고, 그 후 더해진 숫자와 문자열과의 병합이 발생합니다.

이처럼 이항 덧셈 연산자 +는 문자열 연결과 변환이라는 특별한 기능을 제공합니다. 다른 산술 연산자가 오직 숫자형의 피연산자만 다루고, 피연산자가 숫자형이 아닌 경우에 그 형을 숫자형으로 바꾸는 것과는 대조적입니다.

아래 예제는 뺄셈 -과 나눗셈 / 연산자가 어떻게 문자형 피연산자를 다루는지 보여줍니다.

console.log(6 - '2'); // 4, '2'를 숫자로 바꾼 후 연산이 진행됩니다.
console.log('6' / '2'); // 3, 두 피연산자가 숫자로 바뀐 후 연산이 진행됩니다.

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

덧셈 연산자 +는 이항 연산자뿐만 아니라 단항 연산자로도 사용할 수 있습니다.

숫자에 단항 덧셈 연산자를 붙이면 이 연산자는 아무런 동작도 하지 않습니다. 그러나 피연산자가 숫자가 아닌 경우엔 숫자형으로의 변환이 발생합니다.

// 숫자에는 아무런 영향을 미치지 않습니다.
let x = 1;
console.log( +x ); // 1

let y = -2;
console.log( +y ); // -2

// 숫자형이 아닌 피연산자는 숫자형으로 변화합니다.
console.log( +true ); // 1
console.log( +"" );   // 0

단항 덧셈 연산자는 짧은 문법으로도 Number(...)와 동일한 일을 할 수 있게 해줍니다.

개발을 하다 보면 문자열을 숫자로 변환해야 하는 경우가 자주 생깁니다. 대표적으로 HTML 폼(form) 필드에서 값을 가져왔는데 그 값이 문자형일 경우를 예로 들 수 있습니다. 실제로 폼에서 가져온 값은 대개 문자열 형태입니다.

이항 덧셈 연산자를 사용하면 아래와 같이 값이 문자열로 변해서 연결됩니다.

let apples = "2";
let oranges = "3";

console.log(apples + oranges); // 23, 이항 덧셈 연산자는 문자열을 연결합니다.

원하는 대로 값을 더해주려면, 단항 덧셈 연산자를 사용해 피연산자를 숫자형으로 변화시키면 됩니다.

let apples = "2";
let oranges = "3";

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

// `Number(...)`를 사용해서 같은 동작을 하는 코드를 작성할 수 있지만, 더 기네요.
// console.log( Number(apples) + Number(oranges) ); // 5

위 코드를 살펴보면 이항 덧셈 연산자가 적용되기 전에 단항 덧셈 연산자가 먼저 적용됩니다. 그 이유는 바로 "연산자 우선순위"때문입니다.

연산자 우선순위

하나의 표현식에 둘 이상의 연산자가 존재할 경우, 실행 순서는 연산자의 우선순위에 의해 결정됩니다.

1 + 2 * 2라는 식이 있을 때 일반적인 수학에서는 곱셈이 먼저 연산되고, 그 이후에 덧셈 연산이 진행됩니다. 이런 개념이 연산자 우선순위입니다. 여기서 곱셈은 덧셈보다 더 높은 우선순위를 가지고 있습니다.

자바스크립트에서 정의한 연산자 우선순위가 마음에 들지 않는다면, 괄호를 사용하면 됩니다. 괄호 안에 존재하는 연산식은 모든 연산자보다 우선순위가 높기 때문에 자바스크립트에서 정의한 연산자 우선순위를 무력화합니다. 표현식 (1 + 2) * 2에서 괄호로 둘러싼 덧셈 연산식이 먼저 수행되는것을 예로 들 수 있습니다.

자바스크립트는 다양한 연산자를 제공하는데, 이 모든 연산자에는 우선순위가 매겨져 있습니다. 우선순위 숫자가 클수록 먼저 실행됩니다. 순위가 같으면 왼쪽부터 오른쪽으로 연산이 수행됩니다.

아래 테이블은 우선순위 테이블의 일부를 발췌한 표입니다.

순위연산자 이름기호

순위연산자 이름기호
17단항 덧셈+
17단항 부정-
16지수**
15곱셈*
15나눗셈/
13덧셈+
13뺄셈-
3할당=

"단항 덧셈 연산자"는 우선순위 17로 "(이항) 덧셈 연산자"의 우선순위 13보다 높습니다. 표현식 "+apples + oranges"에서 단항 덧셈 연산자가 덧셈보다 먼저 수행되는 이유가 바로 이 때문입니다.

할당 연산자

무언가를 할당할 때 쓰이는 =도 연산자입니다. 이 연산자는 할당 연산자라고 부르며, 우선순위는 3으로 매우 낮습니다.
x = 2 * 2 + 1과 같은 표현식에서 계산이 먼저 이루어지고, 그 결과가 x에 할당되는 이유가 바로 이 때문입니다.

let x = 2 * 2 + 1;

console.log( x ); // 5

값을 반환하는 할당 연산자

자바스크립트에서 대부분의 연산자들은 값을 반환합니다. +-뿐만 아니라 = 역시 값을 반환합니다.
x = value을 호출하면 valuex에 쓰여지고, 이에 더하여 value가 반환됩니다.

let a = 1;
let b = 2;

let c = 3 - (a = b + 1);

console.log(a); // 3
console.log(c); // 0​

위 예제에서 표현식 (a = b + 1)a에 값을 할당하고, 그 값인 3을 반환합니다. 그리고 반환 값은 이어지는 표현식에 사용됩니다.

다만, 위 예제는 할당 연산자의 속성의 이해를 돕기 위한 예제일 뿐 직접 코드를 작성할 때는 이러한 방식을 사용하지 않는것을 권장합니다.
이런 트릭을 사용하면 코드가 명확하지 않을 뿐만 아니라 가독성도 떨어지기 때문입니다.

할당 연산자 체이닝

할당 연산자는 아래와 같이 여러 개를 연결할 수도 있습니다(체이닝).

let a, b, c;

a = b = c = 2 + 2;

console.log(a); // 4
console.log(b); // 4
console.log(c); // 4

위 예제처럼 할당 연산자를 여러 개 연결한 경우, 연산은 우측부터 진행됩니다. 먼저 가장 우측의 2 + 2가 연산되고, 그 결과가 좌측의 c, b, a에 순차적으로 할당됩니다. 모든 변수가 단일 값을 공유하게됩니다.

하지만 되도록이면 연산자를 체이닝 하는것 보다 가독성을 위해 아래 예제와 같이 줄을 나눠 코드를 작성하는것을 권장합니다.

let a, b, c

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와 동일).

console.log(n); // 14

이러한 "복합 할당" 연산자는 산술 연산자와 비트 연산자에도 적용할 수 있습니다. /=, -=등의 연산자를 만들 수 있습니다.

복합 할당 연산자의 우선순위는 할당 연산자와 동일합니다. 따라서 대부분 다른 연산자가 실행된 후에 복합 할당 연산자가 실행됩니다.

let n = 2;

n *= 3 + 5;

console.log(n); // 16  (*=의 우측이 먼저 연산되므로, 위 식은 n *= 8과 동일합니다.)

증가, 감소 연산자

숫자를 1만큼 증가시키거나 감소시키는 것은 자주 사용되는 연산입니다.

  • 증가 연산자 ++는 변수의 값을 1만큼 증가시킵니다.

    let counter = 2;
    counter++; // counter = counter + 1과 동일하게 동작합니다. 하지만 식은 더 짧습니다.
    console.log(counter); // 3​
  • 감소 연산자 --는 변수의 값을 1만큼 감소시킵니다.

    let counter = 2;
    counter--; // counter = counter - 1과 동일하게 동작합니다. 하지만 식은 더 짧습니다.
    console.log(counter); // 1​

++, --연산자는 변수에만 사용 가능하며, 변수의 앞이나 뒤에 올 수 있습니다.

  • counter++와 같이 피연산자 뒤에 올 때는, 후위형이라고 부릅니다.
  • ++counter와 같이 피연산자 앞에 올 때는, 전위형이라고 부릅니다.

후위형과 전위형은 피연산자인 counter1만큼 증가시켜 준다는 점에서 동일한 일을 합니다.

두 형의 차이는 ++/--의 반환 값을 사용할 때 드러납니다.

모든 연산자는 값을 반환합니다. 증가/감소 연산자도 마찬가지로 값을 반환합니다. 아래는 증가/감소 연산자의 위치에 따라 반환되는 값입니다.

  • 전위형은 증가/감소 후의 새로운 값을 반환합니다.
  • 후위형은 증가/감소 전의 기존 값을 반환합니다.

아래 예제를 통해 차이점을 직관적으로 확인할 수 있습니다.

let counter = 1;
let a = ++counter; // (*)

console.log(a); // 2

(*)로 표시한 줄의 후위형 counter++counter를 증가시키긴 하지만, 증가 전의 기존값을 반환합니다. 따라서 1이 출력됩니다.

증가 감소 연산자에 대한 내용을 정리하면 다음과 같습니다.

  • 반환 값을 사용하지 않는 경우라면, 전위형과 후위형엔 차이가 없습니다.

    let counter = 0;
    counter++;
    ++counter;
    console.log(counter); // 2, 위 두 라인은 동일한 연산을 수행합니다.​​
  • 값을 증가시키고 난 후, 증가한 값을 바로 사용하려면 전위형 증가 연산자를 사용해야합니다.

    let counter = 0;
    console.log(++counter); // 1​
  • 값을 증가시키지만, 증가 전의 기존값을 사용하려면 후위형 증가 연산자를 사용해야합니다.

    let counter = 0;
    console.log(counter++); // 0​​

비트 연산자

비트 연산자는 인수를 32비트 정수로 변환하여 이진 연산을 수행합니다.

이런 비트 조작 관련 연산자는 자바스크립트뿐만 아니라 대부분의 프로그래밍 언어에서 지원합니다.

아래는 비트 연산시 사용되는 연산자 목록입니다.

  • 비트 AND ( & )
  • 비트 OR ( | )
  • 비트 XOR ( ^ )
  • 비트 NOT ( ~ )
  • 왼쪽 시프트 (LEFT SHIFT) ( << )
  • 오른쪽 시프트 (RIGHT SHIFT) ( >> )
  • 부호 없는 오른쪽 시프트 (ZERO-FILL RIGHT SHIFT) ( >>> )

비트 연산자는 저수준(2진 표현)에서 숫자를 다뤄야 할 때 사용되므로 흔히 사용되지는 않습니다.

쉼표 연산자

쉼표 연산자 , 는 좀처럼 보기 힘들고, 특이한 연산자 중 하나입니다. 코드를 짧게 쓰려는 의도로 가끔 사용됩니다.

쉼표 연산자는 여러 표현식을 코드 한 줄에서 수행되도록 해줍니다. 이때 표현식 각각이 모두 수행되지만, 마지막 표현식의 수행 결과만 반환되는 점에 유의해야합니다.

let a = (1 + 2, 3 + 4);
console.log(a); // 7 (3 + 4의 연산 결과)

위 예시에서 첫 번째 표현식 1 + 2는 수행은 되지만 그 결과값은 버려집니다. 3 + 4만 수행되어 a에 할당됩니다.

쉼표 연산자는 여러 동작을 하나의 라인에서 처리하려는 복잡한 구조에서 사용합니다. 그 중 하나가 반복문 for입니다.

// 한 줄에서 세 개의 연산이 수행됨
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 ...
}

쉼표 연산자를 이용한 트릭은 자바스크립트의 여러 프레임워크에서 볼 수 있습니다. 쉼표 연산자의 사용 빈도가 높지 않지만, 알아두어야 하는 이유입니다. 다만 쉼표 연산자는 가독성에 도움이 되지는 않으므로 권장하지 않습니다.

profile
Web frontend developer

0개의 댓글