Menu

자바스크립트 연산자 완벽 정리: 산술·비교·논리·할당

계산하고, 값을 비교하고, 불리언을 조합하고, 값을 대입할 때 쓰는 자바스크립트 연산자들 — 실무에서 진짜 발목 잡는 함정까지 같이 짚어봅니다.

연산자는 표현식이 일을 하는 방식이다

자바스크립트에서 어떤 의미 있는 한 줄이든, 그 안에는 반드시 연산자가 들어 있다. 연산자는 한두 개의 값을 받아 새로운 값을 만들어내는 기호다. +는 더하고, ===는 비교하고, &&는 불리언을 결합하고, ? :는 두 값 중 하나를 골라준다. 대부분은 다른 언어에서도 익숙한 모습이지만, 몇 가지는 자바스크립트 특유의 묘한 동작이 있어서 미리 알아두는 게 좋다.

자바스크립트 연산자를 카테고리별로 하나씩 살펴보자. 자주 쓰지는 않지만 꼭 필요한 순간이 오는 연산자들은 마지막에 다룬다.

산술 연산자

자바스크립트 산술 연산자는 예상 그대로 동작한다:

index.js
Output
Click Run to see the output here.

짚고 넘어갈 만한 포인트 몇 가지:

  • /는 항상 부동소수점 나눗셈입니다. 7 / 23이 아니라 3.5가 나와요. 정수 결과가 필요하면 Math.floor(7 / 2)Math.trunc(7 / 2)를 사용하세요.
  • %는 수학적인 모듈로(modulo)가 아니라 나머지(remainder) 연산입니다. 결과 부호는 왼쪽 피연산자를 따라가요. -7 % 32가 아니라 -1입니다.
  • +는 오버로딩되어 있어요. 한쪽이 문자열이면 덧셈이 아니라 문자열 연결(concatenation)로 동작합니다. 예를 들어 "3" + 1"31"이죠. 이 부분은 곧 더 자세히 다룹니다.

증가·감소 연산자

index.js
Output
Click Run to see the output here.

count++++count의 차이는 같은 줄에서 그 표현식의 값을 사용할 때만 의미가 있습니다. 단독 문장으로 쓰면 결과는 똑같아요. 대부분의 스타일 가이드는 가독성을 위해 count += 1을 권장합니다.

+ 연산자는 두 얼굴을 가진다

이 부분은 누구나 한 번쯤은 걸려 넘어지는 지점입니다:

index.js
Output
Click Run to see the output here.

피연산자 중 하나라도 문자열이면 +는 문자열 연결 연산자로 동작해서 반대쪽 값도 문자열로 변환합니다. 반대로 나머지 산술 연산자는 전부 문자열을 숫자로 변환해 버립니다:

index.js
Output
Click Run to see the output here.

핵심만 짚고 가자면, 문자열을 만들 때는 템플릿 리터럴(`price: ${5}`)을 쓰는 게 낫다. 반면에 계산을 해야 할 때는 입력값이 진짜 숫자인지 확인하자. Number(x)parseInt(x, 10)으로 명시적으로 변환하면 된다.

자바스크립트 비교 연산자

비교 연산자는 결과로 불리언을 돌려준다. 종류는 크게 두 가지, 엄격 비교와 느슨한 비교다.

index.js
Output
Click Run to see the output here.

===!==엄격 비교 연산자라서 값과 타입이 모두 같아야 true를 반환합니다. 반면 ==!=는 비교 전에 타입을 강제로 변환하기 때문에 null == undefinedtrue가 되거나 [] == falsetrue가 되는 황당한 상황이 벌어지죠. 그래서 기본적으로는 ===!==를 쓰는 게 정답입니다. 예외적으로 자주 쓰는 패턴은 x == null 정도인데, "xnull이거나 undefined인가?"를 한 번에 체크할 수 있어서 편합니다.

크기 비교 연산자는 숫자일 때는 예상대로 동작하고, 문자열일 때는 알파벳(사전) 순으로 비교합니다:

index.js
Output
Click Run to see the output here.

문자열 비교는 문자 코드 기준으로 이뤄지기 때문에 대소문자를 구분합니다. 사람이 보기에 자연스러운 정렬이 필요하다면 String.prototype.localeCompare를 사용하세요.

논리 연산자 (&&, ||, !)

&&(AND), ||(OR), !(NOT)은 불리언 값을 조합할 때 쓰지만, 단순한 불 대수보다 훨씬 재미있는 동작을 보여줍니다.

index.js
Output
Click Run to see the output here.

여기서 재밌는 점 하나. &&||는 사실 truefalse를 돌려주지 않습니다. 둘 중 하나의 _피연산자_를 그대로 반환하죠. &&는 처음 만나는 falsy 값을 반환하고, 모두 truthy라면 맨 마지막 값을 내놓습니다. 반대로 ||는 처음 만나는 truthy 값을 반환하고, 전부 falsy라면 마지막 값을 돌려줍니다.

index.js
Output
Click Run to see the output here.

그래서 const displayName = user.name || "Guest" 같은 패턴을 자주 보게 되는 겁니다. 비어 있지 않은 첫 번째 값을 골라주는 방식이죠. 간결하긴 한데 한 가지 주의할 점이 있어요. ||0, "", false도 "비어 있는 값"으로 보고 fallback을 작동시킵니다. 만약 이런 값들이 정상적인 값으로 쓰여야 한다면, 아래에서 소개할 널 병합 연산자 ??를 쓰는 게 맞습니다.

두 연산자 모두 단락 평가(short-circuit) 방식으로 동작합니다. 왼쪽만으로 결과가 이미 정해진다면 오른쪽은 아예 실행되지 않아요.

index.js
Output
Click Run to see the output here.

널 병합 연산자 ??

??||와 비슷하지만, null이나 undefined일 때만 동작합니다. 0, "", false 같은 값에는 반응하지 않아요.

index.js
Output
Click Run to see the output here.

값이 falsy여도 유효할 수 있는 경우(숫자 0, 빈 문자열, 명시적 false 등)에는 ??를 쓰고, falsy면 무조건 "없는 값"으로 처리하고 싶을 때는 ||를 쓰면 됩니다. 요즘 코드에서는 null/undefined가 아닌 기본값을 다룰 때 ??가 더 안전한 기본 선택입니다.

자바스크립트 할당 연산자

=는 값을 할당합니다. 여기에 다른 연산자를 결합한 복합 할당 연산자도 있습니다:

index.js
Output
Click Run to see the output here.

논리 할당 연산자도 있습니다. ||=, &&=, ??= 세 가지인데, 현재 값이 특정 조건을 만족할 때만 값을 할당합니다:

index.js
Output
Click Run to see the output here.

if 문을 장황하게 쓰지 않고도 기본값을 채워 넣을 때 아주 유용한 연산자들이죠.

자바스크립트 삼항 연산자

condition ? a : bif/else를 표현식 형태로 쓴 것이라고 보면 됩니다. 조건이 truthy면 a를, 아니면 b를 반환합니다:

index.js
Output
Click Run to see the output here.

삼항 연산자는 값을 간단히 골라낼 때 빛을 발합니다. 반대로 중첩하기 시작하면 금세 읽기 힘들어지죠. a ? b : c ? d : e 같은 코드를 쓰고 있다면, if/else나 조회용 객체(lookup object)로 바꾸는 편이 낫습니다.

typeofinstanceof 연산자

typeof 연산자는 피연산자의 타입을 나타내는 문자열을 반환합니다:

index.js
Output
Click Run to see the output here.

꼭 기억해둬야 할 함정이 두 가지 있습니다. typeof null"object"를 반환한다는 점(1995년부터 있던 버그인데 이제는 수정할 수 없게 굳어버렸습니다), 그리고 배열도 "object"로 찍힌다는 점입니다. 배열인지 확인할 때는 Array.isArray(x), null 체크는 x === null을 쓰세요.

instanceof는 어떤 객체가 특정 생성자로부터 만들어졌는지 확인할 때 사용합니다:

index.js
Output
Click Run to see the output here.

스프레드와 레스트는 똑같이 ...를 씁니다

... 문법은 두 가지 맥락에서 등장합니다. 먼저 스프레드(spread) 로 쓰이면, 이터러블을 개별 요소로 펼쳐줍니다:

index.js
Output
Click Run to see the output here.

_rest_로 쓰일 때는 여러 값을 하나의 배열로 모아주는 역할을 합니다. 주로 함수 매개변수나 구조 분해 할당에서 사용하죠:

index.js
Output
Click Run to see the output here.

같은 문법, 정반대 역할. 스프레드는 펼치고, 레스트는 모읍니다. 둘 중 어느 쪽으로 동작할지는 문맥이 결정합니다. 호출이나 리터럴 안에서는 펼치는 역할이 되고, 매개변수 목록이나 구조 분해 패턴 안에서는 모으는 역할이 됩니다.

연산자 우선순위 (헷갈리면 그냥 괄호)

자바스크립트 연산자에는 우선순위가 있어서, 여러 개를 섞어 쓰면 어떤 연산이 먼저 실행될지 미리 정해져 있습니다. 곱셈은 덧셈보다 먼저, 비교는 논리연산자보다 먼저 실행되는 식이죠:

index.js
Output
Click Run to see the output here.

전체 연산자 우선순위 표는 길고, 이걸 전부 외우는 사람은 없습니다. 99%의 상황에서 통하는 간단한 습관이 있는데요. 여러 연산자를 섞어 쓸 때 순서가 확실하지 않다면, 그냥 괄호를 치세요. 코드 가독성도 좋아지고, 읽는 사람의 기억력에 의존하지 않아도 됩니다.

비트 연산자 (웬만하면 쓸 일 없습니다)

그래도 완성도를 위해 짚고 넘어가자면, &, |, ^, ~, <<, >>, >>> 같은 연산자는 정수의 이진 표현을 다룰 때 사용합니다. 그래픽 처리 코드나 저수준 프로토콜, 혹은 플래그 비트마스크를 쓰는 일부 API에서 가끔 마주치게 됩니다.

index.js
Output
Click Run to see the output here.

흔히 쓰이지만 권장하지는 않는 트릭이 하나 있습니다. 바로 n | 0으로 숫자를 32비트 정수로 잘라내는 방법인데요, 예전에는 Math.trunc보다 빠르다는 이유로 남용되곤 했습니다. 하지만 쓰지 마세요. Math.trunc가 훨씬 명확하고, 32비트 범위를 벗어나는 숫자에도 잘 동작합니다.

다음 주제: if/else

연산자는 값을 만들어내고, if/else는 그 값을 보고 어떤 코드 블록을 실행할지 결정합니다. 위에서 살펴본 비교 연산자와 논리 연산자의 결과는 결국 대부분 조건문에 들어가서 쓰이게 됩니다. 바로 다음 페이지에서 다룰 내용이죠.

자주 묻는 질문

자바스크립트의 주요 연산자에는 어떤 것들이 있나요?

크게 보면 산술(+, -, *, /, %, **), 비교(===, !==, <, >), 논리(&&, ||, !), 할당(=, +=, -=) 연산자가 있고, 여기에 삼항 연산자 ? :, typeof, 널 병합 연산자 ?? 같은 특수한 것들이 더해집니다. 표현식과 제어 흐름을 만드는 기본 재료라고 보면 됩니다.

자바스크립트에서 ==와 ===의 차이는 뭔가요?

===는 값과 타입이 모두 같은지를 비교합니다. 반면 ==는 비교하기 전에 타입을 강제로 변환하기 때문에 0 == "0"true지만 0 === "0"false입니다. 기본적으로는 ===를 쓰는 게 안전합니다. ==의 형 변환 규칙은 생각보다 미묘해서 코드 리뷰에서도 놓치기 쉬운 버그의 원인이 됩니다.

삼항 연산자는 언제 쓰나요?

조건 ? a : b 형태로, 값을 반환하는 한 줄짜리 if/else라고 생각하면 됩니다. 조건이 참(truthy)이면 a, 아니면 b를 평가합니다. 예를 들어 const label = count === 1 ? 'item' : 'items'처럼 짧은 조건식에 유용한데, 중첩해서 쓰기 시작하면 가독성이 급격히 떨어지니 주의하세요.

||대신 ??를 써야 하는 경우는 언제인가요?

||0, "", false 같은 falsy 값 전부를 걸러내고 기본값으로 넘어갑니다. 반면 ??는 오직 null이나 undefined일 때만 기본값을 사용합니다. 예를 들어 count ?? 10처럼 0을 정상적인 값으로 유지하고 싶다면 ??를, 모든 falsy 값을 기본값으로 대체하고 싶다면 ||를 쓰면 됩니다.

Coddy로 코딩 배우기

시작하기