Movatterモバイル変換


[0]ホーム

URL:


MDN Web Docs

Operator precedence

Operator precedence determines how operators are parsed concerning each other. Operators with higher precedence become the operands of operators with lower precedence.

Try it

console.log(3 + 4 * 5); // 3 + 20// Expected output: 23console.log(4 * 3 ** 2); // 4 * 9// Expected output: 36let a;let b;console.log((a = b = 5));// Expected output: 5

Precedence and associativity

Consider an expression describable by the representation below, where bothOP1 andOP2 are fill-in-the-blanks for OPerators.

a OP1 b OP2 c

The combination above has two possible interpretations:

(a OP1 b) OP2 ca OP1 (b OP2 c)

Which one the language decides to adopt depends on the identity ofOP1 andOP2.

IfOP1 andOP2 have different precedence levels (see the table below), the operator with the higherprecedence goes first and associativity does not matter. Observe how multiplication has higher precedence than addition and executed first, even though addition is written first in the code.

js
console.log(3 + 10 * 2); // 23console.log(3 + (10 * 2)); // 23, because parentheses here are superfluousconsole.log((3 + 10) * 2); // 26, because the parentheses change the order

Within operators of the same precedence, the language groups them byassociativity.Left-associativity (left-to-right) means that it is interpreted as(a OP1 b) OP2 c, whileright-associativity (right-to-left) means it is interpreted asa OP1 (b OP2 c). Assignment operators are right-associative, so you can write:

js
a = b = 5; // same as writing a = (b = 5);

with the expected result thata andb get the value 5. This is because the assignment operator returns the value that is assigned. First,b is set to 5. Then thea is also set to 5 — the return value ofb = 5, a.k.a. right operand of the assignment.

As another example, the unique exponentiation operator has right-associativity, whereas other arithmetic operators have left-associativity.

js
const a = 4 ** 3 ** 2; // Same as 4 ** (3 ** 2); evaluates to 262144const b = 4 / 3 / 2; // Same as (4 / 3) / 2; evaluates to 0.6666...

Operators are first grouped by precedence, and then, for adjacent operators that have the same precedence, by associativity. So, when mixing division and exponentiation, the exponentiation always comes before the division. For example,2 ** 3 / 3 ** 2 results in 0.8888888888888888 because it is the same as(2 ** 3) / (3 ** 2).

For prefix unary operators, suppose we have the following pattern:

OP1 a OP2 b

whereOP1 is a prefix unary operator andOP2 is a binary operator. IfOP1 has higher precedence thanOP2, then it would be grouped as(OP1 a) OP2 b; otherwise, it would beOP1 (a OP2 b).

js
const a = 1;const b = 2;typeof a + b; // Equivalent to (typeof a) + b; result is "number2"

If the unary operator is on the second operand:

a OP2 OP1 b

Then the binary operatorOP2 must have lower precedence than the unary operatorOP1 for it to be grouped asa OP2 (OP1 b). For example, the following is invalid:

js
function* foo() {  a + yield 1;}

Because+ has higher precedence thanyield, this would become(a + yield) 1 — but becauseyield is areserved word in generator functions, this would be a syntax error. Luckily, most unary operators have higher precedence than binary operators and do not suffer from this pitfall.

If we have two prefix unary operators:

OP1 OP2 a

Then the unary operator closer to the operand,OP2, must have higher precedence thanOP1 for it to be grouped asOP1 (OP2 a). It's possible to get it the other way and end up with(OP1 OP2) a:

js
async function* foo() {  await yield 1;}

Becauseawait has higher precedence thanyield, this would become(await yield) 1, which is awaiting an identifier calledyield, and a syntax error. Similarly, if you havenew !A;, because! has lower precedence thannew, this would become(new !) A, which is obviously invalid. (This code looks nonsensical to write anyway, since!A always produces a boolean, not a constructor function.)

For postfix unary operators (namely,++ and--), the same rules apply. Luckily, both operators have higher precedence than any binary operator, so the grouping is always what you would expect. Moreover, because++ evaluates to avalue, not areference, you can't chain multiple increments together either, as you may do in C.

js
let a = 1;a++++; // SyntaxError: Invalid left-hand side in postfix operation.

Operator precedence will be handledrecursively. For example, consider this expression:

js
1 + 2 ** 3 * 4 / 5 >> 6

First, we group operators with different precedence by decreasing levels of precedence.

  1. The** operator has the highest precedence, so it's grouped first.
  2. Looking around the** expression, it has* on the right and+ on the left.* has higher precedence, so it's grouped first.* and/ have the same precedence, so we group them together for now.
  3. Looking around the*// expression grouped in 2, because+ has higher precedence than>>, the former is grouped.
js
   (1 + ( (2 ** 3) * 4 / 5) ) >> 6// │    │ └─ 1. ─┘        │ │// │    └────── 2. ───────┘ │// └────────── 3. ──────────┘

Within the*// group, because they are both left-associative, the left operand would be grouped.

js
   (1 + ( ( (2 ** 3) * 4 ) / 5) ) >> 6// │    │ │ └─ 1. ─┘     │    │ │// │    └─│─────── 2. ───│────┘ │// └──────│───── 3. ─────│──────┘//        └───── 4. ─────┘

Note that operator precedence and associativity only affect the order of evaluation ofoperators (the implicit grouping), but not the order of evaluation ofoperands. The operands are always evaluated from left-to-right. The higher-precedence expressions are always evaluated first, and their results are then composed according to the order of operator precedence.

js
function echo(name, num) {  console.log(`Evaluating the ${name} side`);  return num;}// Exponentiation operator (**) is right-associative,// but all call expressions (echo()), which have higher precedence,// will be evaluated before ** doesconsole.log(echo("left", 4) ** echo("middle", 3) ** echo("right", 2));// Evaluating the left side// Evaluating the middle side// Evaluating the right side// 262144// Exponentiation operator (**) has higher precedence than division (/),// but evaluation always starts with the left operandconsole.log(echo("left", 4) / echo("middle", 3) ** echo("right", 2));// Evaluating the left side// Evaluating the middle side// Evaluating the right side// 0.4444444444444444

If you are familiar with binary trees, think about it as apost-order traversal.

                /       ┌────────┴────────┐echo("left", 4)         **                ┌────────┴────────┐        echo("middle", 3)  echo("right", 2)

After all operators have been properly grouped, the binary operators would form a binary tree. Evaluation starts from the outermost group — which is the operator with the lowest precedence (/ in this case). The left operand of this operator is first evaluated, which may be composed of higher-precedence operators (such as a call expressionecho("left", 4)). After the left operand has been evaluated, the right operand is evaluated in the same fashion. Therefore, all leaf nodes — theecho() calls — would be visited left-to-right, regardless of the precedence of operators joining them.

Short-circuiting

In the previous section, we said "the higher-precedence expressions are always evaluated first" — this is generally true, but it has to be amended with the acknowledgement ofshort-circuiting, in which case an operand may not be evaluated at all.

Short-circuiting is jargon for conditional evaluation. For example, in the expressiona && (b + c), ifa isfalsy, then the sub-expression(b + c) will not even get evaluated, even if it is grouped and therefore has higher precedence than&&. We could say that the logical AND operator (&&) is "short-circuited". Along with logical AND, other short-circuited operators include logical OR (||), nullish coalescing (??), and optional chaining (?.).

js
a || (b * c); // evaluate `a` first, then produce `a` if `a` is "truthy"a && (b < c); // evaluate `a` first, then produce `a` if `a` is "falsy"a ?? (b || c); // evaluate `a` first, then produce `a` if `a` is not `null` and not `undefined`a?.b.c; // evaluate `a` first, then produce `undefined` if `a` is `null` or `undefined`

When evaluating a short-circuited operator, the left operand is always evaluated. The right operand will only be evaluated if the left operand cannot determine the result of the operation.

Note:The behavior of short-circuiting is baked in these operators. Other operators wouldalways evaluate both operands, regardless if that's actually useful — for example,NaN * foo() will always callfoo, even when the result would never be something other thanNaN.

The previous model of a post-order traversal still stands. However, after the left subtree of a short-circuiting operator has been visited, the language will decide if the right operand needs to be evaluated. If not (for example, because the left operand of|| is already truthy), the result is directly returned without visiting the right subtree.

Consider this case:

js
function A() { console.log('called A'); return false; }function B() { console.log('called B'); return false; }function C() { console.log('called C'); return true; }console.log(C() || B() && A());// Logs:// called C// true

OnlyC() is evaluated, despite&& having higher precedence. This does not mean that|| has higher precedence in this case — it's exactlybecause(B() && A()) has higher precedence that causes it to be neglected as a whole. If it's re-arranged as:

js
console.log(A() && C() || B());// Logs:// called A// called B// false

Then the short-circuiting effect of&& would only preventC() from being evaluated, but becauseA() && C() as a whole isfalse,B() would still be evaluated.

However, note that short-circuiting does not change the final evaluation outcome. It only affects the evaluation ofoperands, not howoperators are grouped — if evaluation of operands doesn't have side effects (for example, logging to the console, assigning to variables, throwing an error), short-circuiting would not be observable at all.

The assignment counterparts of these operators (&&=,||=,??=) are short-circuited as well. They are short-circuited in a way that the assignment does not happen at all.

Table

The following table lists operators in order from highest precedence (18) to lowest precedence (1).

Several general notes about the table:

  1. Not all syntax included here are "operators" in the strict sense. For example, spread... and arrow=> are typically not regarded as operators. However, we still included them to show how tightly they bind compared to other operators/expressions.
  2. Some operators have certain operands that require expressions narrower than those produced by higher-precedence operators. For example, the right-hand side of member access. (precedence 17) must be an identifier instead of a grouped expression. The left-hand side of arrow=> (precedence 2) must be an arguments list or a single identifier instead of some random expression.
  3. Some operators have certain operands that accept expressions wider than those produced by higher-precedence operators. For example, the bracket-enclosed expression of bracket notation[ … ] (precedence 17) can be any expression, even comma (precedence 1) joined ones. These operators act as if that operand is "automatically grouped". In this case we will omit the associativity.
PrecedenceAssociativityIndividual operatorsNotes
18: groupingn/aGrouping
(x)
[1]
17: access and call left-to-rightMember access
x.y
[2]
Optional chaining
x?.y
n/aComputed member access
x[y]
[3]
new with argument list
new x(y)
[4]
Function call
x(y)
import(x)
16: newn/anew without argument list
new x
15: postfix operatorsn/aPostfix increment
x++
[5]
Postfix decrement
x--
14: prefix operatorsn/aPrefix increment
++x
[6]
Prefix decrement
--x
Logical NOT
!x
Bitwise NOT
~x
Unary plus
+x
Unary negation
-x
typeof x
void x
delete x[7]
await x
13: exponentiationright-to-leftExponentiation
x ** y
[8]
12: multiplicative operatorsleft-to-rightMultiplication
x * y
Division
x / y
Remainder
x % y
11: additive operatorsleft-to-rightAddition
x + y
Subtraction
x - y
10: bitwise shiftleft-to-rightLeft shift
x << y
Right shift
x >> y
Unsigned right shift
x >>> y
9: relational operatorsleft-to-rightLess than
x < y
Less than or equal
x <= y
Greater than
x > y
Greater than or equal
x >= y
x in y
x instanceof y
8: equality operatorsleft-to-rightEquality
x == y
Inequality
x != y
Strict equality
x === y
Strict inequality
x !== y
7: bitwise ANDleft-to-rightBitwise AND
x & y
6: bitwise XORleft-to-rightBitwise XOR
x ^ y
5: bitwise ORleft-to-rightBitwise OR
x | y
4: logical ANDleft-to-rightLogical AND
x && y
3: logical OR, nullish coalescingleft-to-rightLogical OR
x || y
Nullish coalescing operator
x ?? y
[9]
2: assignment and miscellaneousright-to-leftAssignment
x = y
[10]
Addition assignment
x += y
Subtraction assignment
x -= y
Exponentiation assignment
x **= y
Multiplication assignment
x *= y
Division assignment
x /= y
Remainder assignment
x %= y
Left shift assignment
x <<= y
Right shift assignment
x >>= y
Unsigned right shift assignment
x >>>= y
Bitwise AND assignment
x &= y
Bitwise XOR assignment
x ^= y
Bitwise OR assignment
x |= y
Logical AND assignment
x &&= y
Logical OR assignment
x ||= y
Nullish coalescing assignment
x ??= y
right-to-leftConditional (ternary) operator
x ? y : z
[11]
right-to-leftArrow
x => y
[12]
n/ayield x
yield* x
Spread
...x
[13]
1: commaleft-to-rightComma operator
x, y

Notes:

  1. The operand can be any expression.
  2. The "right-hand side" must be an identifier.
  3. The "right-hand side" can be any expression.
  4. The "right-hand side" is a comma-separated list of any expression with precedence > 1 (i.e., not comma expressions). The constructor of anew expression cannot be an optional chain.
  5. The operand must be a valid assignment target (identifier or property access). Its precedence meansnew Foo++ is(new Foo)++ (a syntax error) and notnew (Foo++) (a TypeError: (Foo++) is not a constructor).
  6. The operand must be a valid assignment target (identifier or property access).
  7. The operand cannot be an identifier or aprivate element access.
  8. The left-hand side cannot have precedence 14.
  9. The operands cannot be a logical OR|| or logical AND&& operator without grouping.
  10. The "left-hand side" must be a valid assignment target (identifier or property access).
  11. The associativity means the two expressions after? are implicitly grouped.
  12. The "left-hand side" is a single identifier or a parenthesized parameter list.
  13. Only valid inside object literals, array literals, or argument lists.

The precedence of groups 17 and 16 may be a bit ambiguous. Here are a few examples to clarify.

  • Optional chaining is always substitutable for its respective syntax without optionality (barring a few special cases where optional chaining is forbidden). For example, any place that acceptsa?.b also acceptsa.b and vice versa, and similarly fora?.(),a(), etc.
  • Member expressions and computed member expressions are always substitutable for each other.
  • Call expressions andimport() expressions are always substitutable for each other.
  • This leaves four classes of expressions: member access,new with arguments, function call, andnew without arguments.
    • The "left-hand side" of a member access can be: a member access (a.b.c),new with arguments (new a().b), and function call (a().b).
    • The "left-hand side" ofnew with arguments can be: a member access (new a.b()) andnew with arguments (new new a()()).
    • The "left-hand side" of a function call can be: a member access (a.b()),new with arguments (new a()()), and function call (a()()).
    • The operand ofnew without arguments can be: a member access (new a.b),new with arguments (new new a()), andnew without arguments (new new a).

Help improve MDN

Learn how to contribute.

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp