모던 JavaScript 튜토리얼 - 기본 연산자와 수학

crewd·2021년 1월 6일
0
post-thumbnail

모던 자바스크립트 튜토리얼

ko.javascript.info

기본 연산자와 수학

이번 챕터에서는 자바스크립트에서만 제공하는 연산자에 대해 알아보자

용어: '단항', '이항', '피연산자'

  • 피연산자(oerand)는 연산자가 연산을 수행하는 대상이다.
    5 * 2에서는 왼쪽 피연산자 5와 오른쪽 피연산자 2, 총 두개의 피연산자가 있다.
    '피연산자'는 '인수(argument)'라는 용어로도 불린다.

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

let x = 1;

x = -x;
alert(x); // -1, 단항 마이너스 연산자는 부호를 뒤집는다.
  • 두 개의 피연산자를 받는 연산자는 이항(binary) 연산자 라고 부른다.
    마이너스 연산자는 아래와 같이 이항 연산자로도 쓸 수도 있다.
let x = 1, y = 3;
alert( y - x ); // 2, 이항 마이너스 연산자는 뺄셈을 해준다.

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

수학

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

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

나머지 연산자 %

나머지 연산자(remainder operator)는 %기호로 나타내지만 비율을 나타내는 퍼센트와는 관련이 없다.
나머지 연산자를 사용한 표현식 a % bab로 나눈 후 그 나머지(remainder)를 정수로 반환해준다.

alert( 5 % 2 ); // 5를 2로 나눈 후의 나머지인 1을 출력
alert ( 8 % 3 ); // 8을 3으로 나눈 후의 나머지인 2를 출력

거듭제곱 연산자 **

거듭 제곱 연산자(exponentiation operator)를 사용한 a ** bab번 곱한 값이 반환된다.

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 거듭제곱은 세제곱근)

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

이항 연산자 +의 피연산자로 문자열이 전달되면 덧셈 연산자는 덧셈이 아닌 문자열을 병합(연결)해준다.

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(...)와 동일한 일을 할 수 있게 해준다.

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

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

// `Number(...)`를 사용하면 같은 동작을 하지만 코드가 더 길다.
alert( Number(apples) + Number(oranges) ); // 5

연산자 우선순위

하나의 표현식에 둘 이상의 연산자가 있는 경우, 실행 순서는 연산자의 우선순위(precedence) 에 의해 결정된다.
1 + 2 * 3의 식에서 곱셈이 먼저 연산되는 것과 같은 개념이 연산자 우선순위다.
연산자 우선순위를 사용하지 않으려면 괄호를 사용하면 된다. 괄호는 모든 연산자보다 우선순위가 높기 때문이다.

아래는 우선 순위 테이블의 일부를 발췌한 표다. 우선 순위의 순서를 기억할 필요는 없지만 동일한 기호의 단항 연산자는 이항 연산자보다 우선순위가 더 높다는 것에 주목하자.

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

할당 연산자

무언가를 할당할 때 쓰이는 = 연산자는 할당(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);

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 = b;

복합 할당 연산자

프로그램을 짜다보면, 변수에 연산자를 적용하고 그 결과를 같은 변수에 저장해야 하는 경우가 종종 생긴다.

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과 동일)

증가·감소 연산자

숫자를 하나 늘리거나 줄이는 것은 자주 사용되는 연산이다.
자바스크립트에서는 이런 연산을 해주는 연산자를 제공한다.

  • 증가(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)'이라고 부른다.

후위형과 전위형은 피연산자인 counter1만큼 증가시켜준다는 점에서 동일한 일을 한다.
두 형의 차이는 ++/--의 반환 값을 사용 할 때 드러난다.

전위형은 증가/감소 후의 새로운 값을 반환하는 반면, 후위형은 증가/감소 전의 기존 값을 반환한다.

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

alert(a); // 2

(*)로 표시한 줄의 전위형 ++countercounter를 증가시키고 새로운 값 2를 반환한다.

let counter = 1;
let a = counter++; // (*) ++counter를 counter++로 바꿈

alert(a); //1

(*)로 표시한 줄의 후위형 counter++counter를 증가시키기는 하지만 증가 전의 기존값을 반환한다.

✔ 다른 연산자 사이의 증가/감소 연산자

++/-- 연산자를 표현식 중간에 사용하는 것도 가능하다.
이때, 증가/감소 연산자의 우선순위는 다른 대부분의 산술 연산자보다 높기 때문에, 평가가 먼저 이뤄진다.

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) (>>>)

비트 연산자는 저수준(2진표현)에서 숫자를 다뤄야 할 때 쓰이므로 흔하게 쓰이진 않는다.
웹 개발시에는 이런 일이 자주 일어나지 않기 때문에 비트 연산자를 만날 일은 거의 없다.
그렇다해도 암호를 다워야 할 땐 비트 연산자가 유용하기 때문에 때가되면 MDN의 비트연산자를 보는 것을 추천한다.

쉼표 연산자

쉼표 연산자(comma operator) ,는 좀처럼 보기 힘들고, 특이한 연산자 중 하나다.

쉼표 연산자 ,는 여러 표현식을 코드 한 줄에서 평가할 수 있게 해준다.
이때 표현식이 각각이 모두 평가되지만, 마지막 표현식의 평가 결과만 반환되는 점에 유의해야 한다.

let a = ( 1 + 2, 3 + 4 );

alert(a); // 7, 3 + 4의 결과

✔ 쉼표의 우선순위는 매우 낮다.
쉼표 연산자의 우선순위는 할당 연산자 =보다 더 낮다.
따라서 위 예시에서는 괄호가 중요한 역할을 한다.

괄호가 없으면 a = 1 + 2, 3 + 4에서 +가 먼저 수행되어 a = 3, 7이 된다.
할당 연산자 =는 쉼표 연산자보다 우선순위가 높기 때문에 a = 3이 먼저 실행되고
나머지(7)는 무시된다.

쉼표 연산자는 여러 동작을 하나의 줄에서 처리하려는 복잡한 구조에서 이를 사용한다.

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

쉼표 연산자를 사용한 트릭은 여러 자바스크립트 프레임워크에서 볼 수 있다.
이 연산자의 사용 빈도가 높지 않지만 언급하고 넘어가는 이유이다.

쉼표 연산자는 코드 가독성에 도움이 되지 않으므로 곰곰이 생각해 본 후 진짜 필요한 경우에만 사용하자.

✔ 과제


전위형과 후위형

중요도: 5

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

let a = 1, b = 1;

let c = ++a; // ?
let d = b++; // ?

해답

a = 2
b = 2
c = 2
d = 1

let a = 1, b = 1;

alert( ++a ); // 2, 전위형은 증가 후의 값을 반환합니다.
alert( b++ ); // 1, 후위형은 증가 전의 값을 반환합니다.

alert( a ); // 2, 값이 1만큼 증가합니다.
alert( b ); // 2, 값이 1만큼 증가합니다.

할당 후 결과 예측하기

중요도: 3

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

let a = 2;

let x = 1 + (a *= 2);

해답

a = 4
기존 값 2에 2를 곱한 값

x = 5
1 + 4의 결과 값


덧셈 고치기

중요도: 5

아래 코드는 사용자에게 숫자 2개를 입력받은 다음 그 합을 보여줍니다.

그런데 의도한 대로 예시가 동작하지 않습니다. 프롬프트 창에 세팅한 기본값을 수정하지 않은 경우 덧셈의 결과는 12가 됩니다.

왜 그럴까요? 예시가 제대로 동작하도록 코드를 수정해 보세요. 결과는 3이 되어야 합니다.

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

alert(a + b); // 12

해답

프롬프트 창에서 입력한 값은 문자열로 반환하기 때문에
각각 "1", "2"가 된다.

Number()를 사용하거나 변수 앞에 +를 붙여주면 문자열을 숫자로 변환해준다.

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

alert(a + b);
profile
공부

0개의 댓글