[9] JavaScript 연산자 (1)

SeoChanhee·2020년 10월 15일
0
2.8 기본 연산자와 수학

연산자 우선순위

하나의 표현식에 둘 이상의 연산자가 있는 경우, 실행 순서는 연산자의 우선순위(precedence)에 의해 결정됩니다. 우선순위를 모두 외우기보다는 필요할 때마다 참조하는 것이 좋습니다.

참고: MDN - 우선순위 테이블


1. 산술 연산자

+, -, *, /, %

거듭제곱 연산자 (**)

8 ** (1/3); // 2 (1/3 거듭제곱은 세제곱근)

덧셈 연산자 (+)

이항 덧셈 연산자와 문자열 연결 (문자열 결합 연산자)

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

// '+' 의 문자열 연결
  "my" + "string";	// mystring
  '1' + 2;		// "12"
  2 + '1';		// "21"
  2 + 2 + '1';		// '221'이 아니라 '41'이 출력됩니다.

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

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

덧셈 연산자 +는 이항 연산자뿐만 아니라 단항 연산자로도 사용할 수 있습니다.
숫자에 단항 덧셈 연산자를 붙이면 이 연산자는 아무런 동작도 하지 않습니다. 그러나 피연산자가 숫자가 아닌 경우엔 숫자형으로의 변환이 일어납니다.

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

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

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

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

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

2. 할당 연산자 (=, 대입 연산자)

무언가를 할당할 때 쓰이는 =도 연산자입니다. 이 연산자는 할당(assignment) 연산자라고 불리는데, 우선순위는 3으로 아주 낮습니다.

값을 반환하는 할당 연산자

=는 연산자이기 때문에 흥미로운 함축성을 내포하고 있습니다. 자바스크립트에서 대부분의 연산자는 값을 반환합니다. +-뿐만 아니라 = 역시 값을 반환하죠.
x = value을 호출하면 valuex에 쓰이고, 이에 더하여 value가 반환됩니다.

할당 연산자 체이닝

할당 연산자는 여러 개를 연결할 수도 있습니다(체이닝). a = b = c = 2 + 2;
이렇게 할당 연산자를 여러 개 연결한 경우, 평가는 우측부터 진행됩니다. 먼저 가장 우측의 2 + 2가 평가되고, 그 결과가 좌측의 c, b, a에 순차적으로 할당됩니다. 모든 변수가 단일 값을 공유하게 되죠.
그런데 되도록 연산자를 체이닝 하는 것 보다 가독성을 위해 아래와 같이 줄을 나눠 코드를 작성하길 권유 드립니다.

복합 할당 연산자

+=, *=, /=, -=


3. 증가•감소 연산자 (증감 연산자)

++, -- (전위형 / 후위형)

  1. 증가/감소 연산자는 변수에만 쓸 수 있습니다. 5++와 같이 값에 사용하려고 하면 에러가 발생합니다.
  2. 전위형은 증가/감소 후의 새로운 값을 반환하는 반면, 후위형은 증가/감소 전의 기존 값을 반환합니다.
  3. ++/-- 연산자를 표현식 중간에 사용하는 것도 가능합니다. 이때, 증가/감소 연산자의 우선순위는 다른 대부분의 산술 연산자보다 높기 때문에, 평가가 먼저 이뤄집니다. (하지만 한 줄에서 여러 가지 일을 동시에 하고 있기 때문에 코드의 가독성이 떨어집니다.)

4. 비트 연산자

참고: MDN - 비트 연산자


5. 쉼표 연산자 (,)

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

  let a = (1 + 2, 3 + 4);
  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++) {
   ...
  }

쉼표 연산자를 사용한 트릭은 여러 자바스크립트 프레임워크에서 볼 수 있습니다. 쉼표 연산자 또한 코드 가독성에 도움이 되지 않습니다.


2.9 비교 연산자

6. 비교 연산자

>, <, >=, <=, ==, !=, ===, !==

불린형 반환

다른 연산자와 마찬가지로 비교 연산자 역시 값을 반환합니다. 반환 값은 불린형입니다. 반환된 불린값은 다른 여타 값처럼 변수에 할당 할 수 있습니다.

문자열 비교

자바스크립트는 '사전’ 순으로 문자열을 비교합니다. 실제 단어를 사전에 실을 때 단어를 구성하는 문자 하나하나를 비교하여 등재 순서를 정하는 것과 같이 자바스크립트도 문자열을 구성하는 문자 하나하나를 비교해가며 문자열을 비교합니다.

다른 형을 가진 값 간의 비교

비교하려는 값의 자료형이 다르면 자바스크립트는 이 값들을 숫자형으로 바꿉니다. 불린값의 경우 true1, false0으로 변환된 후 비교가 이뤄집니다.

'2' > 1; // true, 문자열 '2'가 숫자 2로 변환된 후 비교가 진행된다.
'01' == 1; // true, 문자열 '01'이 숫자 1로 변환된 후 비교가 진행된다.
true == 1; // true
false == 0; // true

let a = 0;
alert( Boolean(a) ); // false

let b = "0";
alert( Boolean(b) ); // true

alert(a == b); // true!

일치 연산자 (===)

동등 연산자(equality operator) ==0false를 구별하지 못한다.
일치 연산자(strict equality operator) ===를 사용하면 형 변환 없이 값을 비교할 수 있다.

null이나 undefined 비교하기

산술 연산자나 기타 비교 연산자 <, >, <=, >=를 사용하여 nullundefined를 비교할 경우 nullundefined는 숫자형으로 변환된다. null0, undefinedNaN으로 변한다.

  null === undefined; // false(두 값의 자료형이 다르기 때문에 일치 비교 시 거짓이 반환됨)
  null == undefined; // true
  • null vs 0
  null > 0;  // false (null이 숫자형으로 변환돼 0이 되기 때문)
  null == 0; // false (형 변환을 하지 않음)
  null >= 0; // true (null이 숫자형으로 변환돼 0이 되기 때문)

  // `동등 연산자 ==`는 피연산자가 `undefined`나 `null`일 때 형 변환을 하지 않는다. `undefined`와 `null`을 비교하는 경우에만 `true`를 반환하고, 그 이외의 경우(`null`이나 `undefined`를 다른 값과 비교할 때)는 무조건 `false`를 반환한다.
  • 비교가 불가능한 undefined
  alert( undefined > 0 ); // false (1)
  alert( undefined < 0 ); // false (2)
  alert( undefined == 0 ); // false (3)
  
  // (1)과 (2)에선 `undefined`가 `NaN`으로 변환되는데(숫자형으로의 변환), `NaN`이 피연산자면 비교 연산자는 항상 `false`를 반환한다. `undefined`는 `null`이나 `undefined`와 같고, 그 이외의 값과는 같지 않기 때문에 (3)은 `false`를 반환한다.
  • 함정 피하기
    1. 일치 연산자 ===를 제외한 비교 연산자의 피연산자에 undefinednull이 오지 않도록 특별히 주의하시기 바랍니다.
    2. 또한, undefinednull이 될 가능성이 있는 변수가 >=, >, <, <=의 피연산자가 되지 않도록 주의하시기 바랍니다. 명확한 의도가 있지 않은 이상 말이죠. 만약 변수가 undefinednull이 될 가능성이 있다고 판단되면, 이를 따로 처리하는 코드를 추가하시기 바랍니다.

2.10 if와 '?' 를 사용한 조건 처리

불린형으로의 변환

  • 숫자 0, 빈 문자열"", null, undefined, NaN은 불린형으로 변환 시 모두 false가 됩니다. 이런 값들은 ‘falsy(거짓 같은)’ 값이라고 부릅니다.
  • 이 외의 값은 불린형으로 변환시 true가 되므로 ‘truthy(참 같은)’ 값이라고 부릅니다.

7. 조건부 연산자 '?' (삼항 연산자)

조건부 연산자는 물음표 ?로 표시합니다. 피연산자가 세 개이기 때문에 조건부 연산자'삼항(ternary) 연산자’라고 부르는 사람도 있습니다. 참고로, 자바스크립트에서 피연산자가 3개나 받는 연산자는 조건부 연산자가 유일합니다.

  let result = condition ? value1 : value2;
  // 평가 대상인 condition이 truthy라면 value1이, 그렇지 않으면 value2가 반환된다.
  let accessAllowed;
  let age = prompt('나이를 입력해 주세요.', '');

  if (age > 18) {
    accessAllowed = true;
  } else {
    accessAllowed = false;
  }

//  '조건부 연산자’를 사용하면 위 예시를 더 짧고 간결하게 변형할 수 있다.
  let accessAllowed = (age > 18) ? true : false;
  // 조건문을 괄호로 감싸지 않아도 연산자 우선순위 규칙에 따라, 비교 연산 'age > 18'이 먼저 실행된다.
  // 하지만 코드의 가독성 향상을 위해 괄호를 사용할 것을 권유합니다.

다중 '?'

  let age = prompt('나이를 입력해주세요.', 18);

  let message = (age < 3) ? '아기야 안녕?' :
    (age < 18) ? '안녕!' :
    (age < 100) ? '환영합니다!' :
    '나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!';
// if..else를 사용하면 위 예시를 아래와 같이 변형할 수 있다.
  if (age < 3) {
    message = '아기야 안녕?';
  } else if (age < 18) {
    message = '안녕!';
  } else if (age < 100) {
    message = '환영합니다!';
  } else {
    message = '나이가 아닌 값을 입력 하셨군요!';
  }

부적절한 '?'

  let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');

  (company == 'Netscape') ?
     alert('정답입니다!') : alert('오답입니다!');

위 예시에선 평가 결과를 변수에 할당하지 않고, 결과에 따라 실행되는 표현식이 달라지도록 하였습니다.
그런데 이런 식으로 물음표 연산자를 사용하는 것은 좋지 않습니다.
개발자 입장에선 if 문을 사용할 때 보다 코드 길이가 짧아진다는 점 때문에 물음표 ?if 대용으로 쓰는 게 매력적일 순 있습니다. 하지만 이렇게 코드를 작성하면 가독성이 떨어집니다.

// 아래는 if를 사용해 변형한 코드입니다.
  let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');

  if (company == 'Netscape') {
    alert('정답입니다!');
  } else {
    alert('오답입니다!');
  }
  // 코드를 읽을 때 우리의 눈은 수직으로 움직입니다. 수평으로 길게 늘어진 코드보단 여러 줄로 나뉘어 작성된 코드 블록이 더 읽기 쉽죠. 물음표 연산자 ?는 조건에 따라 반환 값을 달리하려는 목적으로 만들어졌습니다. 이런 목적에 부합하는 곳에 물음표를 사용하시길 바랍니다. 여러 분기를 만들어 처리할 때는 if를 사용하세요.


마침

  1. 연산자의 종류가 정말 많고 다양하다. 이름에 집착하지 말고 어떻게 쓰이는지를 숙지하자.
  2. 코드를 짧게 쓰는 것만이 중요한 것이 아니다. 가독성이 중요하다.
  3. 가장 헷갈리는 부분은 산술 연산자일치 연산자를 제외한 비교 연산자에서 nullundefined가 숫자형으로 변환되는 부분이다. 이로 인해 매우 헷갈리는 결과가 발생한다. 그러므로 명확한 의도를 갖지 않은 한 undefinednull가 피연산자에 되지 않게 주의해야 한다.

더 공부할 내용

  1. 외울 필요는 없지만 그래도 연산자 우선순위 한 번 더 보기 (10) 산술연산자 - TCP SCHOOL)
  2. 필요할 경우, 비트 연산자를 더 공부하기 (MDN - 비트 연산자)
  3. nullundefined가 피연산자일 경우의 상황 다시 보기


출처: 모던 JavaScript 튜토리얼,
TCP SCHOOL - 3. 연산자

0개의 댓글