Skip to content

JavaScript Operator Precedence: Mastering the Rules of Evaluation Order

Remember the "multiply and divide before add and subtract" rule from elementary math? In JavaScript, operators have similar precedence rules. Just like traffic rules determine who goes first, operator precedence determines which operation executes first in complex expressions. Understanding these rules helps you write correct and readable code.

Why Do We Need Precedence?

Look at a simple example:

javascript
let result = 3 + 4 * 5;
console.log(result); // 23, not 35!

Why is it 23 and not 35? Because multiplication (*) has higher precedence than addition (+), so 4 * 5 = 20 is calculated first, then 3 + 20 = 23.

If we want to calculate addition first, we need to use parentheses:

javascript
let result = (3 + 4) * 5;
console.log(result); // 35

Precedence Table (High to Low)

Here are the commonly used operators sorted by precedence, with higher numbers indicating higher precedence:

javascript
// Precedence 20: Grouping (parentheses)
(expression)

// Precedence 19: Member access, function call
obj.property
obj[property]
func(args)
new Constructor()

// Precedence 17: Postfix increment/decrement
x++
x--

// Precedence 16: Logical NOT, unary operators, prefix increment/decrement
!x
+x
-x
typeof x
++x
--x

// Precedence 15: Exponentiation
**

// Precedence 14: Multiplication, division, modulo
*
/
%

// Precedence 13: Addition, subtraction
+
-

// Precedence 12: Bitwise shift
<<
>>
>>>

// Precedence 11: Relational operators
<
<=
>
>=
in
instanceof

// Precedence 10: Equality operators
==
!=
===
!==

// Precedence 9-5: Bitwise operators
&
^
|

// Precedence 6: Logical AND
&&

// Precedence 5: Logical OR
||

// Precedence 4: Nullish coalescing
??

// Precedence 4: Ternary operator
? :

// Precedence 3: Assignment operators
=
+=
-=
*=
/=
etc.

// Precedence 1: Comma operator
,

Common Precedence Examples

Arithmetic Operator Precedence

javascript
// Multiplication/division before addition/subtraction
console.log(2 + 3 * 4); // 14 (first 3*4=12, then 2+12=14)
console.log(10 - 6 / 2); // 7 (first 6/2=3, then 10-3=7)
console.log(8 / 2 + 3); // 7 (first 8/2=4, then 4+3=7)

// Same precedence evaluates left to right
console.log(10 - 3 - 2); // 5 (first 10-3=7, then 7-2=5)
console.log(20 / 4 / 2); // 2.5 (first 20/4=5, then 5/2=2.5)

// Exponentiation before multiplication/division
console.log(2 * 3 ** 2); // 18 (first 3**2=9, then 2*9=18)
console.log(2 ** 3 * 4); // 32 (first 2**3=8, then 8*4=32)

// Use parentheses to change precedence
console.log((2 + 3) * 4); // 20
console.log(2 * (3 + 4)); // 14

Comparison and Logical Operators

javascript
// Comparison before logical operations
let age = 25;
let hasLicense = true;

// First execute age >= 18, get true, then execute true && hasLicense
console.log(age >= 18 && hasLicense); // true

// && before ||
console.log(true || (false && false)); // true (first false && false = false, then true || false = true)
console.log((true || false) && false); // false (change precedence)

// ! before &&
let isWeekend = false;
let isHoliday = false;
console.log(!isWeekend && !isHoliday); // true (first execute both !)

// Practical application
let score = 85;
let attendance = 90;
let passed = score >= 80 && attendance >= 85;
console.log(passed); // true

Assignment Operators Have Lowest Precedence

Assignment operators have very low precedence, almost always executing last:

javascript
let a, b, c;

// First calculate the right expression, then assign
a = 5 + 3; // First 5+3=8, then assign to a
console.log(a); // 8

b = 10 > 5; // First compare, get true, then assign to b
console.log(b); // true

c = 2 + 3 * 4 > 10; // First 3*4=12, then 2+12=14, then 14>10=true, finally assign
console.log(c); // true

Unary Operator Precedence

Unary operators have high precedence:

javascript
// typeof has higher precedence than arithmetic operations
console.log(typeof 5 + 3); // "number3" (first typeof 5 = "number", then concatenate)
console.log(typeof (5 + 3)); // "number" (change precedence)

// ! has very high precedence
console.log(!true || false); // false (first !true=false, then false || false)

// Increment/decrement
let x = 5;
let y = ++x * 2; // First ++x = 6, then 6*2=12
console.log(y); // 12
console.log(x); // 6

let a = 5;
let b = a++ * 2; // First use a=5 for calculation 5*2=10, then increment a
console.log(b); // 10
console.log(a); // 6

Associativity

When operators have the same precedence, associativity determines the evaluation order. Most operators are left-associative (left to right), while a few are right-associative (right to left).

Left-Associativity

javascript
// Arithmetic operators: left to right
console.log(10 - 5 - 2); // 3 ((10 - 5) - 2 = 5 - 2 = 3)
console.log(20 / 4 / 2); // 2.5 ((20 / 4) / 2 = 5 / 2 = 2.5)

// Addition: left to right
console.log(1 + 2 + 3 + 4); // 10 (((1 + 2) + 3) + 4)

// String concatenation
console.log("a" + "b" + "c"); // "abc" (("a" + "b") + "c")
console.log(1 + 2 + "3"); // "33" ((1 + 2) + "3" = 3 + "3")
console.log("1" + 2 + 3); // "123" (("1" + 2) + 3 = "12" + 3)

Right-Associativity

javascript
// Assignment operators: right to left
let a, b, c;
a = b = c = 10;
// Execution order: c = 10, then b = 10, finally a = 10
console.log(a, b, c); // 10 10 10

// Ternary operator: right to left
let result = true ? 1 : false ? 2 : 3;
// Execution order: false ? 2 : 3 = 3, then true ? 1 : 3 = 1
console.log(result); // 1

// Exponentiation: right to left (this is special!)
console.log(2 ** (3 ** 2)); // 512 (2 ** (3 ** 2) = 2 ** 9 = 512)
console.log((2 ** 3) ** 2); // 64 (change associativity)

Complex Expression Analysis

Let's analyze some complex expressions:

Example 1: Mixed Operations

javascript
let result = 5 + 3 * 2 - 4 / 2;

// Step-by-step execution:
// 1. 3 * 2 = 6 (multiplication has precedence)
// 2. 4 / 2 = 2 (division has precedence)
// 3. 5 + 6 = 11 (addition)
// 4. 11 - 2 = 9 (subtraction)

console.log(result); // 9

Example 2: Logic and Comparison

javascript
let x = 10;
let y = 20;
let z = 30;

let result = (x < y && y < z) || z < x;

// Step-by-step execution:
// 1. x < y => 10 < 20 = true
// 2. y < z => 20 < 30 = true
// 3. z < x => 30 < 10 = false
// 4. true && true = true
// 5. true || false = true

console.log(result); // true

Example 3: Assignment and Increment

javascript
let a = 5;
let b = a++ + ++a;

// Step-by-step execution:
// 1. a++ uses current value 5, then a becomes 6
// 2. ++a first increments (a becomes 7), then uses 7
// 3. 5 + 7 = 12
// 4. Assign to b

console.log(b); // 12
console.log(a); // 7

Example 4: Conditional and Logic

javascript
let score = 85;
let result = score >= 90 ? "A" : score >= 80 ? "B" : "C";

// Step-by-step execution (right to left):
// 1. Inner condition: score >= 80 ? "B" : "C"
//    85 >= 80 is true, so gets "B"
// 2. Outer condition: score >= 90 ? "A" : "B"
//    85 >= 90 is false, so gets "B"

console.log(result); // "B"

Practical Programming Advice

1. Use Parentheses to Enhance Readability

Even if you know precedence rules, it's recommended to use parentheses to make code more readable:

javascript
// Not clear enough
let result1 = a + b * c - d / e;

// Clearer
let result2 = a + b * c - d / e;

// Complex logic must use parentheses
let canAccess = (isAdmin || isModerator) && !isBanned;

2. Avoid Overly Complex Expressions

javascript
// ❌ Bad: too complex
let result = (a++ + (++b * c--) / --d && e > f) || g <= h ? i : j;

// ✅ Good: break into multiple steps
let temp1 = a++ + (++b * c--) / --d;
let temp2 = temp1 && e > f;
let result = temp2 || g <= h ? i : j;

// Or better: completely separate
let multiplied = ++b * c--;
let divided = multiplied / --d;
let sum = a++ + divided;
let condition1 = sum && e > f;
let condition2 = condition1 || g <= h;
let result = condition2 ? i : j;

3. Beware of Type Conversion Pitfalls

javascript
// String concatenation before number addition
console.log(1 + 2 + "3"); // "33"
console.log("1" + 2 + 3); // "123"
console.log("1" + (2 + 3)); // "15"

// Use parentheses to clarify intent
let total = price + tax; // Number addition
let display = "Total: $" + (price + tax); // Calculate first, then concatenate

4. Be Careful with Short-Circuit Evaluation

javascript
// && short-circuit behavior
let user = null;
let name = user && user.name; // Safe: user is null, won't access name

// But don't overuse
let value = obj && obj.prop && obj.prop.value; // Poor readability

// Use optional chaining for clarity
let value = obj?.prop?.value;

5. Assignment Return Values

Assignment operators return the assigned value, which can be used for chained assignment, but be careful:

javascript
// Chained assignment
let a = (b = c = 0); // All become 0

// Assignment in conditions (easy to confuse)
if ((x = 10)) {
  // This is assignment! Not comparison!
  console.log("Always true");
}

// Should be:
if (x === 10) {
  console.log("Compare");
}

// Intentional conditional assignment should use parentheses
if ((match = text.match(/pattern/))) {
  console.log(match);
}

Precedence Memory Tricks

Basic Rules

  1. Parentheses Highest: () always evaluated first
  2. Member Access and Function Call: ., [], ()
  3. Unary Operators: !, typeof, ++, --, +, -
  4. Exponentiation: ** (right-associative)
  5. Multiplication, Division, Modulo: *, /, %
  6. Addition, Subtraction: +, -
  7. Comparison: <, >, <=, >=
  8. Equality: ==, !=, ===, !==
  9. Logical AND: &&
  10. Logical OR: ||
  11. Ternary: ? :
  12. Assignment: =, +=, etc. (right-associative)

Practical Principles

You don't need to remember all precedences, just the commonly used ones:

  • Multiplication/division before addition/subtraction
  • Comparison before logic
  • && before ||
  • Assignment last
  • Use parentheses when unsure

Common Errors

Error 1: Forgetting Operator Precedence

javascript
// Wrong
if (type === "user" || "admin") {
  // Always true!
  // ...
}

// Correct
if (type === "user" || type === "admin") {
  // ...
}

Error 2: Prefix/Postfix Increment Confusion

javascript
let i = 5;

// Easy to confuse
let a = i++ * 2; // a = 10, i = 6
let b = ++i * 2; // b = 14, i = 7

// Better to write separately
i++;
let a = i * 2; // Clearer

Error 3: Chained Comparisons

javascript
// JavaScript doesn't support chained comparisons
let x = 5;
console.log(1 < x < 10); // true, but not what you think!

// Actual execution:
// 1 < x => 1 < 5 => true
// true < 10 => 1 < 10 => true

// Correct approach
console.log(1 < x && x < 10); // true

Summary

Operator precedence is fundamental to JavaScript expression evaluation. Understanding it helps avoid many subtle bugs.

Key Points Recap:

  • Precedence determines execution order of different operators
  • Associativity determines execution order of same-precedence operators
  • Most operators are left-associative, assignment, ternary, and exponentiation are right-associative
  • Parentheses () have the highest precedence and can change execution order
  • Common precedence: multiplication/division > addition/subtraction > comparison > logical AND > logical OR > assignment
  • For code readability, use parentheses to clarify intent
  • Avoid writing overly complex expressions
  • When unsure, consult documentation or use parentheses