2.8 기본 연산자와 수학
덧셈 +
, 곱셈 *
, 뺄셈 -
과 같은 학교에서 배운 연산자가 아닌 자바스크립트에서만 제공하는 연산자를 학습해보자.
용어: '단항', '이항', '피연산자'
연산자에 대해 학습하기 전에, 앞으로 자주 등장하게 될 용어 몇 가지를 정리
- 피연산자(operand)는 연산자가 연산을 수행하는 대상이다.
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 opeator)는 %
기호로 나타내지만, 비율을 나타내는 퍼센트와 관련이 없다.
나머지 연산자를 사용하는 표현식 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 )
거듭제곱 연산자는 정수가 아닌 숫자에 대해서도 동작한다. 1/2
을 사용하면 제곱근을 구할 수 있다.
alert( 4 ** (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
alert( 8 ** (1/3) ); // 2 (1/3 거듭제곱은 세세제곱근)
이항 연산자 '+' 와 문자열 연결
덧셈 연산자 +
는 대개 숫자를 더한 결과를 반환한다.
그런데 이항 연산자 +
의 피연산자로 문자열이 전달되면 덧셈 연산자는 덧셈이 아닌 문자열을 병합(연결)한다.
let s = "my" + "string";
alert(s)l // 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(...)
와 동일한 일을 할 수 있게 해준다.
개발을 하다 보면 문자열을 숫자로 변환해야 하는 경우가 자주 생긴다. HTM 폼(form) 필드에서 값을 가져왔는데 그 값이 문자형일 때 같이 말이다. 실제로 폼에서 가지고 온 값은 대개 문자열 형태이다.
이항 덧셈 연산자를 사용하면 아래와 같이 값이 문자열로 변해서 연결될 것이다.
let apples = "2";
let oranges = "3";
// 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변화한다.
alert( +apples + +oranges); // 5
// `Number(...)`를 사용해 같은 동작을 하는 코드를 작성할 수 있지만, 더 길다.
// alert(Number(apples) + Number(oranges)); // 5
위 식을 수학자가 본다면 불필요한 덧셈 기호에 대해 언급하며 식이 이상하다고 지적할 것이다. 프로그래머라면 아니겠지만 말이다. 위 식은 우리가 의도한 대로 단항 덧셈 연산자가 먼저 문자열을 숫자로 변환시키고, 이항 덧셈 연산자가 그 결과들을 더해주고 있다.
그런데 왜 이항 덧셈 연산자가 적용되기 전에 단항 덧셈 연산자가 먼저 적용될까? 그 이유는 이제 학습하게 될 연산자 우선순위 때문이다.
연산자 우선순위
하나의 표현식에 둘 이상의 연산자가 있는 경우, 실행 순서는 연산자의 우선순위(precedence) 에 의해 결정된다.
1 + 2 * 2
라는 식이 있을 때 곱셈이 먼저, 그 후에 덧셈이 일어난다는 것을 알고 있을 것이다. 이런 개념이 연산자 우선순위이다. 여기서 곱셈은 덧셈보다 더 높은 우선순위를 가진다.
자바스크립트에서 정의한 연산자 우선순위가 마음에 들지 않는다면, 괄호를 사용하면 된다. 괄호는 모든 연산자보다 우선순위가 높기 때문에 자바스크립트에서 정의한 연산자 우선순위를 무력화 시킨다. 표현식 (1 + 2) * 2
에서 괄호로 둘러싼 덧셈 연산자가 먼저 수행된다는 것 같이 말이다.
자바스크립트는 다양한 연산자를 제공하는데, 이 모든 연산자엔 우선순위가 매겨져 있다. 우선순위 숫자가 클수록 먼저 실행된다. 숫자가 같으면 왼쪽부터 실행해서 오른쪽으로 연산이 수행된다.
순위 | 연산자 이름 | 기호 |
---|---|---|
… | … | … |
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과 동일하다.)
증가,감소 연산자
숫자를 하나 늘리거나 줄이는 것은 자주 사용되는 연산입니다.
자바스크립트에서는 이런 연산을 해주는 연산자를 제공한다.
- 증가(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; // (*)
alert(a) ;; // 2
(*)
로 표시한 줄의 전위형 ++counter
는 counter
를 증가시키고 새로운 값 2
를 반환한다. 따라서 alert
는 2
을 표시한다.
이제 후휘형을 살펴본다.
let counter = 1;
let a = counter++; // (*) ++counter를 counter++로 바꿈
alert(counter); // 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 opeartor)는 인수를 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)의 결과
위 예시에서 첫 번째 표현식인 1 + 2
는 평가가 되지만 그 결과는 버려진다. 3 + 4
만 평가되어 a
에 할당된다.
⚠️ 쉼표 우선순위는 매우 낮다.
쉼표 연산자의 연산자 우선순위는 매우 낮다. 할당 연산자 =
보다 더 낮다. 따라서 위 예시에선 괄호가 중요한 역할을 한다.
괄호가 없으면 a = 1 + 2, 3 + 4
에서 먼저 +
가 수행되어 a = 3, 7
이 된다. 할당 연산자 =
는 쉼표 연산자보다 우선순위가 높기 때문에 a = 3
이 먼저 실행되고, 나머지 (7)
은 무시된다.
(a = 1 + 2), 3 + 4
를 연산한 것처럼 된다.
이렇게 마지막 표현식을 제외한 모든 것을 버리는 연산자는 어디서 사용되는 걸까?
여러 동작을 하나의 줄에서 처리하려는 복잡한 구조에서 이를 사용한다.
예)
// 한 줄에 세 개의 연산이 수행됨
let (a = 1, b = 3, c = a * b; a < 10; a++) {
...
}
쉼표 연산자를 사용한 트릭은 여러 자바스크립트 프레임워크에서 볼 수 있다. 이 연산자의 사용 빈도가 높지 않지만, 언급하고 넘어가는 이유이다. 쉼표 연산자는 코드 가독성에 도움이 되지 않는다. 따라서 곰곰이 생각해 본 후 , 진짜 필요할 경우에만 사용하도록 한다.
✅ 과제
전위형과 후위형
아래 코드가 실행된 후, 변수 a
, b
, c
, d
엔 각각 어떤 값들이 저장될까?
let a = 1, b = 1;
let c = ++a; //
let d = b++; //
해답
let a = 1, b = 1;
alert( ++a ); // 2, 전위형은 증가 후의 값을 반환
alert( b++ ); // 1, 후위형은 증가 전의 값을 반환
alert( a ); // 2, 값이 1만큼 증가
alert( b ); // 2, 값이 1만큼 증가
a = 2
b = 2
c = 2
d = 1
할당 후 결과 예측하기
아래 코드가 실행되고 난 후, a
와 x
엔 각각 어떤 값이 저장될까?
let a = 2;
let x = 1 + (a *= 2);
해답
a = 4
x = 5
형 변환
아래 표현식들의 결과를 예측해보자.
"" + 1 + 0 // "10" (1)
"" - 1 + 0 // -1 (2)
true + false // 1
6 / "3" // 2
"2" * "3" // 6
4 + 5 + "px" // "9px'
"$" + 4 + 5 // "$45"
"4" - 2 // 2
"4px" - 2 // NaN
7 / 0 // Infinity
" -9 " + 5 // "-9 5" (3)
" -9 " - 5 // -14 (4)
null + 1 // 1 (5)
undefined + 1 // NaN (6)
" \t \n" - 2 // -2 (7)
- 피 연산자 중 하나가 문자열인
"" + 1
에서1
은 문자형으로 변환된다. 따라서 공백과 문자열 1을 더한,"" + 1 = "1"
과 같은 효과를 발휘한다. 그다음 연산"1" + 0
에도 같은 규칙이 적용된다. - 뺄셈 연산자
-
는 기타 수학 연산자처럼 숫자형만을 인수로 받는다. 빈 문자열""
는 숫자0
으로 변환되기 때문에 결과는1
이 된다. - 피 연산자 중 하나가 문자열이므로 숫자 5가 문자열로 변환된다.
- 뺄셈 연산자는 인수를 숫자형으로 변화시키므로
" -9 "
는 숫자9
로 변한다. - 숫자형으로 변환 시
null
은0
이 된다. undefined
는 숫자형으로 변환시NaN
이 된다.- 문자열이 숫자형으로 변할 땐 문자열 앞뒤의 공백이 삭제된다. 뺄셈 연산자 앞의 피연산자는 공백을 만드는 문자
\t
와\n
, 그 사이의 “일반적인” 공백으로 구성된다. 따라서" \t \n"
는 숫자형으로 변환 시 길이가0
인 문자열로 취급되어 숫자0
이 된다.
덧셈 고치기
아래 코드는 사용자에게 숫자 2개를 입력받은 다음 그 합을 보여준다.
그런데 의도한 대로 예시가 동작하지 않는다. 프롬프트 창에 세팅한 기본값을 수정하지 않은 경우 덧셈의 결과는 12
가 된다. 왜 그럴까? 예시가 제대로 동작하도록 코드를 수정하자. 결과는 3
이 되어야 한다.
let a = prompt("덧셈할 첫 번째 숫자를 입력해주세요.", 1);
let b = prompt("덧셈할 두 번째 숫자를 입력해주세요.", 2);
alert(a + b); // 12
해답
let a = prompt("덧셈할 첫 번째 숫자를 입력해주세요.", 1);
let b = prompt("덧셈할 두 번째 숫자를 입력해주세요.", 2);
alert(+a + +b);
Author And Source
이 문제에 관하여(2.8 기본 연산자와 수학), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jsje02/2.8-기본-연산자와-수학저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)