연산자 우선순위

연산자 우선순위는 연산자를 실행하는 순서를 결정합니다. 우선순위가 높은 연산자가 먼저 실행됩니다.

우선순위와 결합성

아래와 같이 표현할 수 있는 표현식을 생각해 봅시다. 연산자1과 연산자2의 자리에는 아무 연산자를 넣을 수 있습니다.

a 연산자1 b 연산자2 c

두 연산자의 우선순위(아래 표 참조)가 다를 경우, 우선순위가 높은 연산자가 먼저 실행되고 결합성은 영향을 미치지 않습니다. 아래 예제에서는 덧셈이 곱셈보다 먼저 쓰였음에도 곱셈의 우선순위가 높기 때문에 먼저 실행됩니다.

console.log(3 + 10 * 2);   // 23을 출력
console.log(3 + (10 * 2)); // 23을 출력, 괄호는 불필요함
console.log((3 + 10) * 2); // 26을 출력, 괄호로 인해 실행 순서가 바뀜

좌결합성(왼쪽에서 오른쪽으로)은 표현식이 (a 연산자1 b) 연산자2 c와 같이, 우결합성(오른쪽에서 왼쪽으로)은 a 연산자1 (b 연산자2 c)와 같이 계산된다는 의미입니다. 대입 연산자는 우결합성이므로 다음과 같은 코드를 작성할 수 있습니다.

a = b = 5; // a = (b = 5);와 같음

이때 대입 연산자는 대입된 값을 반환하므로 ab의 값이 5가 됨을 예상할 수 있습니다. 우선 b의 값이 5로 설정되고, 그 다음에는 a의 값이 우변인 b = 5의 반환값 5로 설정됩니다.

다른 예시로, 좌결합성인 다른 산술 연산자와 달리 거듭제곱 연산자 (**)만은 우결합성입니다. 흥미로운 점으로 표현식의 평가는 결합성과 무관하게 항상 왼쪽에서 오른쪽으로 진행됩니다.

코드 출력
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 나눗셈 연산자 (/)에 주목
console.log(echo("첫째", 6) / echo("둘째", 2));
첫째 항 평가함
둘째 항 평가함
3
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 거듭제곱 연산자 (**)에 주목
console.log(echo("첫째", 2) ** echo("둘째", 3));
첫째 항 평가함
둘째 항 평가함
8

여러 연산자의 우선순위가 같을 때는 결합성을 고려합니다. 위에서와 같이 연산자가 하나이거나 연산자끼리 우선순위가 다를 경우에는 결합성이 결과에 영향을 미치지 않습니다. 아래의 예제에서 같은 종류의 연산자를 여러 번 사용했을 때 결합성이 결과에 영향을 미치는 것을 확인할 수 있습니다.

코드 출력
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 나눗셈 연산자 (/)에 주목
console.log(echo("첫째", 6) / echo("둘째", 2) / echo("셋째", 3));
첫째 항 평가함
둘째 항 평가함
셋째 항 평가함
1
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 거듭제곱 연산자 (**)에 주목
console.log(echo("첫째", 2) ** echo("둘째", 3) ** echo("셋째", 2));
첫째 항 평가함
둘째 항 평가함
셋째 항 평가함
512
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 첫 번째 거듭제곱 연산자 주변의 괄호에 주목
console.log((echo("첫째", 2) ** echo("둘째", 3)) ** echo("셋째", 2));
첫째 항 평가함
둘째 항 평가함
셋째 항 평가함
64

위의 예제에서 나눗셈은 좌결합성이므로 6 / 3 / 2(6 / 3) / 2와 같습니다. 한편 거듭제곱은 우결합성이므로 2 ** 3 ** 22 ** (3 ** 2)와 같습니다. 그러므로 (2 ** 3) ** 2는 괄호로 인해 실행 순서가 바뀌기 때문에 위 표와 같이 64로 평가됩니다.

우선순위는 결합성보다 항상 우선하므로, 거듭제곱과 나눗셈을 같이 사용하면 나눗셈보다 거듭제곱이 먼저 계산됩니다. 예를 들어 2 ** 3 / 3 ** 2는 (2 ** 3) / (3 ** 2)와 같으므로 0.8888888888888888로 계산됩니다.

예제

3 > 2 && 2 > 1
// true를 반환

3 > 2 > 1
// 3 > 2는 true인데, 부등호 연산자에서 true는 1로 변환되므로
// true > 1은 1 > 1이 되고, 이는 거짓이다.
// 괄호를 추가하면 (3 > 2) > 1과 같다.

다음 표는 우선순위 내림차순(21부터 1까지)으로 정렬되어 있습니다.

우선순위 연산자 유형 결합성 연산자
21 그룹 없음 ( … )
20 멤버 접근 좌결합성 … . …
계산된 멤버 접근 좌결합성 … [ … ]
new (매개변수 리스트 존재) 없음 new … ( … )

함수 호출

좌결합성 … ( )
Optional chaining 좌결합성 ?.
19 new (매개변수 리스트 생략) 우결합성 new …
18 후위 증가 없음 … ++
후위 감소 … --
17 논리 NOT 우결합성 ! …
비트 NOT ~ …
단항 양부호 + …
단항 부정 - …
전위 증가 ++ …
전위 감소 -- …
typeof typeof …
void void …
delete delete …
await await …
16 거듭제곱 우결합성 … ** …
15 곱셈 좌결합성 … * …
나눗셈 … / …
나머지 … % …
14 덧셈 좌결합성 … + …
뺄셈 … - …
13 비트 왼쪽 시프트 좌결합성 … << …
비트 오른쪽 시프트 … >> …
비트 부호 없는 오른쪽 시프트 … >>> …
12 미만 좌결합성 … < …
이하 … <= …
초과 … > …
이상 … >= …
in … in …
instanceof … instanceof …
11 동등 좌결합성 … == …
부등 … != …
일치 … === …
불일치 … !== …
10 비트 AND 좌결합성 … & …
9 비트 XOR 좌결합성 … ^ …
8 비트 OR 좌결합성 … | …
7 널 병합 연산자 좌결합성 … ?? …
6 논리 AND 좌결합성 … && …
5 논리 OR 좌결합성 … || …
4 조건 우결합성 … ? … : …
3 할당 우결합성 … = …
… += …
… -= …
… **= …
… *= …
… /= …
… %= …
… <<= …
… >>= …
… >>>= …
… &= …
… ^= …
… |= …
2 yield 우결합성 yield …
yield* yield* …
1 쉼표 / 시퀀스 좌결합성 … , …