연산자 우선순위
========

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

시도해보기
-----

우선순위와 결합성
---------

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

a 연산자1 b 연산자2 c
```


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


```js
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)`와 같이 계산된다는 의미입니다. 대입 연산자는 우결합성이므로 다음과 같은 코드를 작성할 수 있습니다.


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


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

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

|  |  |
| --- | --- |
| 코드 | 출력 |
| 
```js
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 나눗셈 연산자 (/)에 주목
console.log(echo("첫째", 6) / echo("둘째", 2));
```

 | 
```
첫째 항 평가함
둘째 항 평가함
3
```

 |
| 
```js
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 거듭제곱 연산자 (\*\*)에 주목
console.log(echo("첫째", 2) \*\* echo("둘째", 3));
```
 | 
```
첫째 항 평가함
둘째 항 평가함
8
```
 |

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

|  |  |
| --- | --- |
| 코드 | 출력 |
| 
```js
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 나눗셈 연산자 (/)에 주목
console.log(echo("첫째", 6) / echo("둘째", 2) / echo("셋째", 3));
```

 | 
```
첫째 항 평가함
둘째 항 평가함
셋째 항 평가함
1
```

 |
| 
```js
function echo(name, num) {
    console.log(name + " 항 평가함");
    return num;
}
// 거듭제곱 연산자 (\*\*)에 주목
console.log(echo("첫째", 2) \*\* echo("둘째", 3) \*\* echo("셋째", 2));
```

 | 
```
첫째 항 평가함
둘째 항 평가함
셋째 항 평가함
512
```

 |
| 
```js
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 ** 2`는 `2 ** (3 ** 2)`와 같습니다. 그러므로 `(2 ** 3) ** 2`는 괄호로 인해 실행 순서가 바뀌기 때문에 위 표와 같이 64로 평가됩니다.

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

예제
--


```js
3 > 2 && 2 > 1;
// true를 반환

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

그룹화와 단락에 대한 참고사항
----------------

아래 표에서 그룹화는 우선 순위가 가장 높은 것으로 나열됩니다. 그러나 이것이 항상 그룹화 기호`( … )` 내의 표현식이, 특히 단락과 관련하여 먼저 평가된다는 것을 의미하지는 않습니다.

단락은 조건부 평가의 전문 용어입니다. 예를 들어 표현식 `a &&(b + c)`에서 `a`가 falsy이면 하위 표현식`(b + c)`은 괄호 안에 있어도 평가되지 않습니다. 논리 분리 연산자("OR")가 "단락"되었다고 말할 수 있습니다. 논리적 분리와 함께 다른 단락 연산자에는 논리적 연결("AND"), nullish-coalescing, 선택적 연결 및 조건부 연산자가 포함됩니다. 몇 가지 예가 더 있습니다.


```js
a || b \* c; // `a`를 먼저 평가하고, `a`가 "truthy"라면 `a`를 생성합니다.
a && b < c; // `a`를 먼저 평가하고, `a`가 "falsy"라면 `a`를 생성합니다.
a ?? (b || c); // `a`를 먼저 평가하고, `a`가 `null`과 `undefined`가 아니라면 `a`를 생성합니다.
a?.b.c; // `a`를 먼저 평가하고, `a`가 `null`또는 `undefined`라면 `undefined`를 생성합니다.
```

표
-

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

| 우선순위 | 연산자 유형 | 결합성 | 연산자 |
| --- | --- | --- | --- |
| 19 | 그룹 | 없음 | `( … )` |
| 18 | 멤버 접근 | 좌결합성 | `… . …` |
| 계산된 멤버 접근 | 좌결합성 | `… [ … ]` |
| `new` (인자 리스트 제공) | 없음 | `new … ( … )` |
| 함수 호출 | 좌결합성 | `… ( … )` |
| 옵셔널 체이닝 | 좌결합성 | `?.` |
| 17 | `new` (인자 리스트 생략) | 우결합성 | `new …` |
| 16 | 후위 증가 | 없음 | `… ++` |
| 후위 감소 | `… --` |
| 15 | 논리 NOT | 우결합성 | `! …` |
| 비트 NOT | `~ …` |
| 단항 양부호 | `+ …` |
| 단항 부정 | `- …` |
| 전위 증가 | `++ …` |
| 전위 감소 | `-- …` |
| `typeof` | `typeof …` |
| `void` | `void …` |
| `delete` (en-US) | `delete …` |
| `await` | `await …` |
| 14 | 거듭제곱 | 우결합성 | `… ** …` |
| 13 | 곱하기 | 좌결합성 | `… * …` |
| 나누기 | `… / …` |
| 나머지 | `… % …` |
| 12 | 더하기 | 좌결합성 | `… + …` |
| 빼기 | `… - …` |
| 11 | 비트 왼쪽 시프트 | 좌결합성 | `… << …` |
| 비트 오른쪽 시프트 (en-US) | `… >> …` |
| 비트 부호 없는 오른쪽 시프트 (en-US) | `… >>> …` |
| 10 | 미만 (en-US) | 좌결합성 | `… < …` |
| 이하 (en-US) | `… <= …` |
| 초과 (en-US) | `… > …` |
| 이상 (en-US) | `… >= …` |
| `in` | `… in …` |
| `instanceof` | `… instanceof …` |
| 9 | 동등 | 좌결합성 | `… == …` |
| 부등 | `… != …` |
| 일치 (en-US) | `… === …` |
| 불일치 (en-US) | `… !== …` |
| 7 | 비트 AND | 좌결합성 | `… & …` |
| 7 | 비트 XOR (en-US) | 좌결합성 | `… ^ …` |
| 6 | 비트 OR (en-US) | 좌결합성 | `… | …` |
| 5 | 논리 AND | 좌결합성 | `… && …` |
| 4 | 논리 OR | 좌결합성 | `… || …` |
| 널 병합 연산자 | 좌결합성 | `… ?? …` |
| 3 | 조건 (삼항) | 우결합성 | `… ? … : …` |
| 2 | 할당 (en-US) | 우결합성 | `… = …` |
| `… += …` |
| `… -= …` |
| `… **= …` |
| `… *= …` |
| `… /= …` |
| `… %= …` |
| `… <<= …` |
| `… >>= …` |
| `… >>>= …` |
| `… &= …` |
| `… ^= …` |
| `… |= …` |
| `… &&= …` |
| `… ||= …` |
| `… ??= …` |
| `yield` | 우결합성 | `yield …` |
| `yield*` | `yield* …` |
| 1 | 쉼표 / 시퀀스 | 좌결합성 | `… , …` |