피연산자 ( operand ) 는 연산자가 연산을 수행하는 대상이다.
5 * 2 에는 왼쪽 피연산자 5와 오른쪽 피연산자 2, 총 두 개의 피연산자가 있다.
" 피연산자 " 는 " 인수 ( argument ) " 라는 용어로 불리기도 한다.
let x = 1; x = -x; alert( x ); // - 1 , 단항 마이너스 연산자는 부호를 뒤집는다.
let x = 1, y = 3; alert( y - x ); // 2, 이항 마이너스 연산자는 뺄셈을 해준다.
부호를 반전해주는 단항 마이너스 연산자와 뺄셈에 쓰이는
이항 마이너스 연산자 ( 뺄셈 연산자 ) 는 부호가 같지만 수행하는 연산이 다르다.
두 연산을 구분하는 기준은 피연산자의 개수이다.
덧셈 연산자 +는 대개 숫자를 더한 결과를 반환한다.
그러나, 이항 연산자 [ + ] 의 피연산자로 문자열이 전달되면 ,
덧셈이 아닌 문자열 병합 ( 연결 ) 이 일어난다.
let s = "my" + "string"; alert(s); // mystring
피연산자 중 하나가 문자열이면 다른 하나도 문자열로 변환된다.
alert( '1' + 2 ); // "12" alert( 2 + '1' ); // "21"
첫 번째 피연산자가 문자열인지, 두 번째 피연산자가 문자열인지는 중요하지 않으며,
피연산자 중 어느 하나가 문자열이면 다른 하나도 문자열로 변환된다.
연산은 왼쪽에서 오른쪽으로 진행된다.
두 개의 숫자 뒤에 문자열이 오는 경우 , 숫자가 먼저 더해지고 ,
그 후 더해진 숫자와 문자열과의 병합이 이뤄진다.
alert(2 + 2 + '1' ); // "221"이 아닌 "41"이 출력된다.
이처럼 이항 덧셈 연산자 +는 문자열 연결과 변환이라는 특별한 기능을 제공한다.
다른 산술 연산자가 오직 숫자형의 피연산자만 다루고 ,
피연산자가 숫자형이 아닌 경우에 그 형을 숫자형으로 바꾸는 것과는 대조적이다.
alert( 2 - '1' ); // 1 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 ); // "23"
값을 더해주려면 , 단항 덧셈 연산자를 사용해 피연산자를 숫자형으로 변화시켜야 한다.
let apples = "2"; let oranges = "3"; // 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변화한다. alert( +apples + +oranges ); // 5
연산자 우선순위에 의해 단항 덧셈 연산자가 먼저 적용된 후
이할 덧셈 연산자가 적용되어 수식이 계산된다.
하나의 표현식에 둘 이상의 연산자가 있는 경우,
실행 순서는 연산자의 우선순위 ( precedence ) 에 의해 결정된다.
자바스크립트에서 정의한 연산자 우선순위에 어긋나고 싶다면, 괄호를 사용하면 된다.
괄호는 모든 연산자보다 우선순위가 높기 때문에 연산자 우선순위를 무력화시킨다.
동일한 기호의 단항 연산자는 이항 연산자보다 우선순위가 더 높다.
무언가를 할당할 때 쓰이는 할당 연산자 [ = ] 의 우선순위는 3으로 아주 낮다.
let x = 2 * 2 + 1; alert( x ); // 5
x = 2 * 2 + 1 과 같은 표현식에서 계산이 먼저 이뤄지고 ,
그 결과가 x에 할당되는 이유가 바로 이 때문이다.
할당 연산자는 여러 개를 연결할 수도 있다. [ 체이닝 ]
let a, b, c; a = b = c = 2 + 2; alert( a ); // 4 alert( b ); // 4 alert( c ); // 4
할당 연산자를 여러 개 연결한 경우 , 평가는 우측부터 진행된다.
먼저 가장 우측의 2 + 2가 평가되고 , 그 결과가 좌측의 c, b, a에 순차적으로 할당된다.
모든 변수가 단일 값을 공유하게 된다.
연산자는 항상 값을 반환하며,
덧셈 [ + ] 또는 곱셈 [ * ] 연산자에선 이런 특징이 명확하게 드러난다.
할당 연산자도 이 규칙을 따르며, 할당 연산자 [ = ] 는 값을 반환한다.
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 을 반환한다. 반환 값은 이어지는 표현식에 사용된다.
나머지 연산자는 [ % ] 기호로 나타내지만 , 비율을 나타내는 퍼센트와는 관련이 없다.
나머지 연산자를 사용한 표현식 a % b 는
a 를 b 로 나눈 후 그 나머지를 정수로 반환해준다.
alert( 5 % 2 ); // 5를 2로 나눈 후 나머지 1 출력 alert( 8 % 3 ); // 8을 3으로 나눈 후 나머지 2 출력 alert( 6 % 3 ); // 6을 3으로 나눈 후 나머지 0 출력
거듭제곱 연산자 ** 는 표준으로 채택된 지 얼마 안 된 연산자 이다.
자연수 b가 있을 때 , 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)
거듭제곱 연산자는 정수가 아닌 숫자에 대해서도 동작한다.
숫자를 하나 늘리거나 줄이는 것은 자주 사용되는 연산이다.
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를 반환한다.
let counter = 1; let a = counter++; alert(a); // 1
후위형 counter++는 counter 를 증가시키긴 하지만 , 증가 전의 기존 값을 반환한다.
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++ ); // 후위형은 기존값을 반환하기 때문에 2가 출력된다.
이렇게 코드를 작성하는 게 기술적으로 문제가 있는 것은 아니지만 ,
한 줄에서 여러 가지 일을 동시에 하고 있기 때문에 코드의 가독성이 떨어진다.
코드를 읽을 때 눈을 빠르게 움직이다 보면 counter++ 와 같은 것을 놓치기 쉬워,
변수가 증가했다는 것을 놓칠 수 있다.
let counter = 1; alert( 2 * counter ); counter++;
" 코드 한 줄엔 , 특정 동작 하나 " 에 관련된 내용만 작성하는 게 좋다.
비트 연산자 ( bitwise operator ) 는 인수를 32비트 정수로 변환하여 이진 연산을 수행한다.
비트 연산이 어떻게 수행되는지 이해하려면 2진 표현에 대해 알아야 한다.
이 연산자를 쓸 일이 거의 없기에, 연산자가 필요할 때
MDN 의 비트 연산자 문서 문서를 찾아보는것을 추천한다.
프로그램을 짜다 보면 , 변수에 연산자를 적용하고
그 결과를 같은 변수에 저장해야 하는 경우가 종종 생긴다.
let n = 2; n = n + 5; n = n * 2;
이때, [ += ] 와 [ *= ] 연산자를 사용하면 짧은 문법으로 동일한 연산을 수행할 수 있다.
let n = 2; n += 5; // 7 ( n = n + 5 ) n *= 2; // 14 ( n = n * 2 ) alert( n ); // 14
복합 할당 연산자는 산술 연산자와 비트 연산자에도 적용할 수 있다.
[ /= ] , [ -= ] 등의 연산자를 만들 수 있다.
let n = 2; n *= 3 + 5; alert( n ); // 16 ( +=의 우측이 먼저 평가되므로 , n *= 8 )
복합 할당 연산자의 우선순위는 할당 연산자와 동일하다.
따라서 대다수의 경우, 다른 연산자가 실행된 후에 복합 할당 연산자가 실행된다.
쉼표 ( comma ) 연산자 [ , ] 는 좀처럼 보기 힘들고 , 특이한 연산자 중 하나이다.
코드를 짧게 쓰려는 의도로 가끔 사용된다.
쉼표 연산자 [ , ] 는 여러 표현식을 코드 한 줄에서 평가할 수 있게 해준다.
이때 표현식 각각이 모두 평가되지만 , 마지막 표현식의 평가 결과만 반환된다.
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++) { ... }
쉼표 연산자를 사용한 트릭은 여러 자바스크립트 프레임워크에서 볼 수 있다.
쉼표 연산자는 코드 가독성에 도움이 되지 않아, 정말 필요한 경우에만 사용하는것이 좋다.
아래 코드가 실행된 후, 변수 a, b, c, d엔 각각 어떤 값들이 저장될까요?
let a = 1, b = 1; let c = ++a; // ? let d = b++; // ?
a = 1 , b = 1 ,
++a 전위형 증가 연산자로 a = 2 가 된 후 c 에 할당 c = 2 ,
b++ 후위형 증가 연산자로 b = 1 의 값을 d 에 할당 d = 1 ,
값이 할당 된 후 b값 증가 b = 2 .
아래 코드가 실행되고 난 후, a와 x엔 각각 어떤 값이 저장될까요?
let a = 2; let x = 1 + (a *= 2);
a = 2 , ( a *= 2 ) 연산을 하여 a = 4 ,
1 + ( 4 ) 의 값을 x 에 할당하여 x = 5 .
아래 표현식들의 결과를 예측해 보세요.
"" + 1 + 0 "" - 1 + 0 true + false 6 / "3" "2" * "3" 4 + 5 + "px" "$" + 4 + 5 "4" - 2 "4px" - 2 7 / 0 " -9 " + 5 " -9 " - 5 null + 1 undefined + 1 " \t \n" - 2
피 연산자 중 하나가 문자열인 "" + 1 에서 1은 문자형으로 변환된다 .
공백과 문자열 1을 더한, "" + 1 = " 1 " 이 된다.
그다음 연산 "1" + 0 = " 10 " 이된다.
뺄셈 연산자 [ - ] 숫자형만을 인수로 받는다.
빈 문자열 [ "" ] 는 숫자 0으로 변환되어 0 - 1 + 0 = -1 이 된다.
true = 1 , false = 0 으로 변환되어, 1 + 0 = 1 이 된다.
나눗셈 연산자 [ / ] 숫자형만을 인수로 받아,
문자열 "3" 은 숫자 3으로 변환되어 6 / 2 = 2 가 된다.
곱셈 연산자 [ * ] 숫자형만을 인수로 받아,
문자열 "2" 은 숫자 2로 , 문자열 "3" 은 숫자 3 으로 변환되어 2 * 3 = 6 이 된다.
4 + 5 가 계산되어 9 + "px" 피 연산자 중 하나가 문자열이므로 숫자 9가
문자열 "0" 로 변환되어 "9" + "px" = "9px"
피 연산자 중 하나가 문자열이므로 숫자 4가 문자열 "4" 로 변환되어,
"$" + "4" = "$4" , 마찬가지로 숫자 5도 문자열 "5" 로 변환되어,
"$4" + "5" = "$45" 가 된다.
뺄셈 연산자 [ - ] 숫자형만을 인수로 받아,
문자열 "4" 는 숫자 4 로 변환되어 4 - 2 = 2 가 된다.
"4px" 는 숫자로 변환할 수 없기 때문에 NaN 이 된다.
실제로 가능하지 않은 계산을 자바스크립트에서 오류로 처리하지 않지만,
0으로 나눗셈한 값을 나타낼 수 없기 때문에 Infinity 이 된다.
피 연산자 중 하나가 문자열이므로 숫자 5가 문자열로 변환되어
" - 9 " + " 5 " = " -9 5 " 가 된다.
곱셈 연산자 [ * ] 숫자형만을 인수로 받아,
문자열 " -9" 는 숫자 9 로 변환하여, -9 - 5 = - 14 가 된다.
null은 숫자형 0 으로 변환되어, 0 + 1 = 1 이 된다.
undefined는 숫자형으로 변환시 NaN 이 된다.
문자열이 숫자형으로 변할 땐 문자열 앞뒤의 공백이 삭제된다.
뺄셈 연산자 앞의 피연산자는 공백을 만드는 문자 \t와 \n, 그 사이의 공백으로 구성된다.
" \t \n"는 숫자형으로 변환 시 길이가 0인 문자열로 취급되어 숫자 0이 된다.
0 -2 = -2 가 된다.