본문 바로가기
FE/JS

[Modern Javascript Deep Dive] #7 연산자

by aeyong-dev 2024. 2. 5.

 연산자(operator)는 하나 이상의 표현식에 연산을 수행해 값을 만든다. 연산의 대상을 피연산자(operand)라 하며, 피연산자는 값으로 평가될 수 있는 표현식이어야 한다(연산을 수행해 새로운 값을 만들어야 하므로). 연산자 표현식 또한 값으로 표현될 수 있는 표현식이다. 

7.1 산술 연산자

 산술 연산자(arithmetic operator)는 말 그대로 수학적 계산을 수행하여 숫자값을 만든다. 만약 불가능하다면 NaN을 return한다. 피연산자의 갯수에 따라 이항 산술 연산자, 단항 산술 연산자로 나뉜다. 

7.1.1 이항(binary) 산술 연산자

 두개의 피연산자를 산술 연산하여 숫자값을 만든다. 부수효과(피연산자의 값을 변경)는 없다.  언제나 새로운 값을 만들어낸다. + 덧셈, - 뺄셈, * 곱셈, / 나눗셈, % 나머지 연산자가 있다. 자세한 설명은 생략한다. 

7. 1. 2 단항(unary) 산술 연산자

 한개의 피연산자를 산술 연산하여 숫자값을 만든다. 

단항 산술 연산자 의미 부수 효과
++ 증가 O
-- 감소 O
+ 효과없음 X
- 부호 반전 X

 

 단항 산술 연산자 ++, --는 부수효과가 있다. 피연산자의 값을 변경하는 암묵적 할당이 이루어진다. 이 둘은 위치에도 의미가 있다. 

  • 전위 증/감 연산자 (prefix increment/decrement operator)
    • 피연산자 앞에 위치 ( ++foo; ) 
    • 피연산자 증감 연산 후 다른 연산 수행
  • 후위 증/감 연산자 (postfix increment/decrement operator)
    • 피연산자 뒤에 위치 ( foo++; ) 
    • 다른 연산 수행 후 피연산자 증감 연산
var x = 5, result;

// 선할당 후증가
result = x++;
console.log(result, x); // 5 6

// 선증가 후할당
result = ++x;
console.log(result, x); // 7 7

 

+ 연산자는 숫자 타입이 아닌 피연산자에 사용하면 숫자 타입으로 변환하여 return한다. 피연산자를 변경하는 것이 아니라 숫자 타입으로 변환한 값을 return한다(부수효과 X). - 연산자도 마찬가지이다. +와 다르게 부호를 반전하는 효과도 있다. 

 

7. 1. 3 문자열 연결 연산자

 + 연산자는 피연산자 중 하나 이상이 문자열일 경우 문자열 연결 연산자로 동작한다. 이 외에는 산술 연산자로 동작한다. 이 때 개발자의 의도와 다르게 자바스크립트 엔진이 강제로 타입을 바꾸기도 한다. 이를 암묵적 타입 변환(implicit coercion) 또는 타입 강제 변환(type coercion)이라 한다. 

 

7. 2 할당 연산자

 할당 연산자(assignment operator)는 말 그대로 할당을 위해 사용된다. var temp = 1; 처럼 좌항의 변수에 우변의 값을 할당한다. 할당을 통해 변수의 값이 변하므로 부수효과가 존재한다. 

 +=, -= 처럼 산술 연산자가 = 앞에 사용되기도 한다. var x = 0; x += 5; 는 x = x+5 와 같은 의미를 지닌다. 우항의 값을 좌항의 변수에 연산하고 할당한다. +는 문자열 연결 연산자로도 사용되므로 +=는 문자열 연결에도 사용될 수 있다. 

var x = 0;
x += 1; // x = 1

var string = 'hi';
string += ' there'; // string = 'hi there'

 

 할당문은 표현식인 문이다. x = 0은 x에 할당된 값인 0으로 평가된다. 이 때문에 아래와 같이 동일 값을 연쇄 할당할 수 있다. 

var a, b, c;
a = b = c = 10;

 할당 연산은 우결합성(우항의 피연산자부터 연산 진행, 7.13 참고)이므로 c부터 할당이 진행된다. 

 

7. 3 비교 연산자(comparison operator)

 좌항과 우항을 비교한 결과를 불리언 타입 값으로 return한다. 조건문, 반복문에서 주로 사용된다. 

7. 3. 1 동등 / 일치 비교 연산자

동등 비교(loose equality) 연산자일치 비교(strict equality) 연산자는 같은 값인지 평가간다. 하지만 영문이름처럼 느슨한 평가인지, 엄격한 평가인지의 차이가 있다. 동등 비교 연산자는 느슨한 비교, 일치 비교 연산자는 엄격한 비교를 한다. 

 동등 비교 연산자는 좌항과 우항의 값이 같은지를 검사하고 결과에 따라 true 또는 false를 return한다. == 를 사용하며, 다른지를 검사할 때는 != 를 사용한다. 

 일치 비교 연산자는 값 뿐만 아니라 타입도 같은지(엄격한 검사) 검사한다. ===, !== 를 사용한다. 

 아래 코드를 보자(안티 패턴: 설계를 지양하는 패턴이므로 이해하지 않아도 됨)

'0' == ''; // false
0 == ''; // true
false == 'false' // false

 이처럼 동등 비교 연산자는 결과를 예측하기 어렵기 때문에 일치 비교 연산자 사용을 지향해야 한다. 

 

 일치 비교 연산자에는 예외가 있는데, NaN은 스스로 일치하지 않는 유일한 값이다. 

NaN === NaN; // false

 숫자가 NaN인지 확인하려면 Number.isNaN() 으로 검사할 수 있다. 

 자바스크립트에는 +0과 -0이 있는데, 이 둘은 동등 비교, 일치 비교 모두 true를 return한다. 

 

7. 3. 2 대소 관계 비교 연산자

 피연산자의 대소관계를 비교하여 불리언 타입 값으로 return한다. 부수 효과는 없다. >, <, <=, >= 가 있다. 

 

7. 4 삼항 조건 연산자

 삼항 조건 연산자(ternary operator)는 평가 결과에 따라 return값이 정해진다. 부수 효과는 없다. 아래는 교재에서 설명하는 방법은 아니지만 필자가 옛날에 이해했던 방법이다. 

result = 0 ? '홀수' : '짝수';
// result = 0인가요? 네 : 아니오;

 ? 앞의 피연산자는 조건식으로, 불리언 값으로 평가될 표현식이다. 평가 결과가 불리언 타입이 아니라면 강제 타입 변환된다. 

 삼항 조건 연산자는 if...else 문과 서로 교체될 수 있지만, 값으로 사용될 수 있는지에 대한 차이가 있다. 삼항 조건 연산자는 값으로 평가될 수 있는 이기 때문이다. if...else문과 삼항 조건 연산자는 가독성이 더 좋은 방식으로 유연하게 사용하는 것이 좋다. 

 

7. 5 논리 연산자

 논리합, 논리곱, 부정에 대한 연산자이다. 좌항과 우항의 피연산자에 대해 논리 연산을 수행한다. 부정 논리 연산자는 좌항이 없고 우항만 존재한다. 각각 &&, ||, ! 을 사용한다. 부수효과는 없다. 

 논리합, 논리곱 연산자 표현식의 평가 결과는 불리언 값이 아닐 수 있다. 이들은 항상 좌항 또는 우항의 피연산자로 평가되는데, 이는 나중에 다시 다루겠다. 여기서 알 수 있는 점은 논리합/곱 연산자는 타입 강제 변환을 수행하지 않는다는 점이다. 하지만 부정 논리 연산자는 다른 연산자들과 마찬가지로 타입이 맞지 않는다면(부정 논리 연산자의 경우 불리언값이 아니라면) 강제 타입 변환을 수행한다. 

 

7. 6 쉼표 연산자

 말 그대로 쉼표를 사용한다. 좌항 피연산자부터 차례대로 평가하고 마지막 피연산자의 평가 값을 return한다.

 

7. 7 그룹 연산자

 소괄호로 피연산자를 감싸면서 사용한다. 수학과 마찬가지로 그룹 연산자로 묶인 표현식을 먼저 평가한다. 프로그램의 실행 순서를 정할 수 있다. 

 

7. 8 typeof 연산자

 피연산자의 데이터 타입을 문자열로 반환한다. string, number, boolean, undefined, symbol, object, function의 7가지 중 하나를 return한다. null은 return되지 않는다. 

 typeof null; 을 수행하면 object를 return하는데 주의하자. 사실 이것은 자바스크립트 초창기의 버그인데, 기존 코드에 영향을 줄 수 있어 수정되지 못하고 현재까지 방치된 버그이다. null타입인지 확인하려면 일치 연산자를 사용해야한다. 

 선언되지 않은 식별자를 피연산자로 하면 에러가 아닌 undefined를 반환한다. 

 

7. 9 지수 연산자

 이전에는 Math.pow() 메서드로 지수 연산을 수행했지만 ES7부터 ** 로 사용한다. 음수를 거듭제곱의 밑으로(좌항에) 사용하려면 그룹 연산자를 사용해야 한다. 다른 산술 연산자와 마찬가지로 할당 연산자와 함께 사용할 수 있다. 

 

7. 10 기타 연산자

?., ??, delete, new 등의 더 많은 연산자가 있지만 앞으로 천천히 알아보자. 

 

7. 11 연산자의 부수효과

 할당 연산자, 증감 연산자, delete 연산자의 경우 다른 코드에 영향을 주는 부수 효과가 있다. 이 외의 연산자들은 다른 코드에 영향을 주지 않고 새로운 값을 생성해서 return한다. 

 

7. 12 연산자 우선순위

 * 연산자는 + 연산자보다 우선순위가 높은 것 처럼 연산자들에는 우선순위가 있다. 이를 외울 필요는 없다. 억지로 외우기 보다 그룹 연산자로 확실하게 순서를 명시해주는 것이 좋다. 

 

7. 13 연산자 결합 순서

 앞서 좌결합성, 우결합성에 대해 잠시 언급한 적 있다. 이는 연산자가 좌항부터 평가하는지, 우항부터 평가하는지를 의미한다. 

  • 좌결합성
    • +, -, /, % 등
  • 우결합성
    • ++, --, 할당 연산자, typeof, delete, ? 등