JavaScript Tutorial

JavaScript Operator Precedence: Complete Guide with Examples

Master JavaScript operator precedence and associativity. Learn the order of operations, precedence table, and how to write clear expressions. Complete guide with practical examples.

Welcome back! šŸ‘‹ You've learned about all the different types of operators in JavaScript. Now, let's explore operator precedence - the rules that determine the order in which operators are evaluated in complex expressions.

Understanding precedence is crucial for writing correct code and avoiding bugs caused by unexpected evaluation order. Let's master this final piece of the operators puzzle!


What is Operator Precedence?

Operator precedence determines the order in which operators are evaluated in an expression containing multiple operators. Operators with higher precedence are evaluated before operators with lower precedence.

Think of it like mathematical order of operations (PEMDAS/BODMAS):

// Just like in math: multiplication before addition
console.log(2 + 3 * 4);  // 14 (not 20!)

// Because * has higher precedence than +
// Evaluated as: 2 + (3 * 4) = 2 + 12 = 14

Why Precedence Matters

// Without understanding precedence
let result = 10 + 5 * 2;
// Is it: (10 + 5) * 2 = 30?
// Or:    10 + (5 * 2) = 20?

console.log(result);  // 20 (* has higher precedence)

// Another example
let x = 5;
let y = 10;
let z = x + y > 10;
// Is it: (x + y) > 10?
// Or:    x + (y > 10)?

console.log(z);  // true (+ has higher precedence than >)
// Evaluated as: (5 + 10) > 10 = 15 > 10 = true

Precedence Levels

JavaScript has 21 precedence levels (from highest to lowest). Here's the complete table:

Complete Precedence Table

Precedence  Operator Type              Associativity   Operators
══════════════════════════════════════════════════════════════════
    21      Grouping                   n/a             ( )
    20      Member Access              left-to-right   .
            Computed Member Access     left-to-right   [ ]
            new (with args)            n/a             new ... ( )
            Function Call              left-to-right   ... ( )
            Optional Chaining          left-to-right   ?.
    19      new (without args)         right-to-left   new ...
    18      Postfix Increment          n/a             ... ++
            Postfix Decrement          n/a             ... --
    17      Logical NOT                right-to-left   ! ...
            Bitwise NOT                right-to-left   ~ ...
            Unary Plus                 right-to-left   + ...
            Unary Negation             right-to-left   - ...
            Prefix Increment           right-to-left   ++ ...
            Prefix Decrement           right-to-left   -- ...
            typeof                     right-to-left   typeof ...
            void                       right-to-left   void ...
            delete                     right-to-left   delete ...
            await                      right-to-left   await ...
    16      Exponentiation             right-to-left   ... ** ...
    15      Multiplication             left-to-right   ... * ...
            Division                   left-to-right   ... / ...
            Remainder                  left-to-right   ... % ...
    14      Addition                   left-to-right   ... + ...
            Subtraction                left-to-right   ... - ...
    13      Bitwise Left Shift         left-to-right   ... << ...
            Bitwise Right Shift        left-to-right   ... >> ...
            Unsigned Right Shift       left-to-right   ... >>> ...
    12      Less Than                  left-to-right   ... < ...
            Less Than or Equal         left-to-right   ... <= ...
            Greater Than               left-to-right   ... > ...
            Greater Than or Equal      left-to-right   ... >= ...
            in                         left-to-right   ... in ...
            instanceof                 left-to-right   ... instanceof ...
    11      Equality                   left-to-right   ... == ...
            Inequality                 left-to-right   ... != ...
            Strict Equality            left-to-right   ... === ...
            Strict Inequality          left-to-right   ... !== ...
    10      Bitwise AND                left-to-right   ... & ...
     9      Bitwise XOR                left-to-right   ... ^ ...
     8      Bitwise OR                 left-to-right   ... | ...
     7      Logical AND                left-to-right   ... && ...
     6      Logical OR                 left-to-right   ... || ...
             Nullish Coalescing        left-to-right   ... ?? ...
     5      Conditional (Ternary)      right-to-left   ... ? ... : ...
     4      Assignment                 right-to-left   ... = ...
                                                       ... += ...
                                                       ... -= ...
                                                       ... &&= ...
                                                       ... ||= ...
                                                       ... ??= ...
                                                       (etc.)
     3      yield                      right-to-left   yield ...
            yield*                     right-to-left   yield* ...
     2      Spread                     n/a             ... ...
     1      Comma                      left-to-right   ... , ...

Grouping (Highest Precedence)

Parentheses ( ) have the highest precedence and force evaluation of their contents first.

Basic Examples

// Without parentheses
console.log(2 + 3 * 4);      // 14 (* first)

// With parentheses
console.log((2 + 3) * 4);    // 20 (+ forced first)

// Multiple levels
console.log(2 * (3 + 4) * 5);  // 70
// Evaluation: 2 * 7 * 5 = 70

// Nested parentheses
console.log(((2 + 3) * 4) - 1);  // 19
// Evaluation: ((5) * 4) - 1 = 20 - 1 = 19

Always Use Parentheses for Clarity

// āŒ Hard to read
let result = a + b * c / d - e;

// āœ… Clear intent
let result = a + ((b * c) / d) - e;

// āŒ Ambiguous
if (a || b && c) { }

// āœ… Explicit
if (a || (b && c)) { }

Member Access (Precedence 20)

Member access has very high precedence.

// Member access before arithmetic
let obj = { value: 5 };
console.log(obj.value + 10);  // 15
// Evaluated as: (obj.value) + 10

// Array access before arithmetic
let arr = [1, 2, 3];
console.log(arr[0] * 2);  // 2
// Evaluated as: (arr[0]) * 2

// Chained access
let data = {
  user: {
    name: "John",
    scores: [10, 20, 30]
  }
};

console.log(data.user.scores[0] + 5);  // 15
// Evaluated as: ((((data.user).scores)[0]) + 5)

Increment/Decrement (Precedence 18/17)

Postfix (Precedence 18)

let x = 5;
console.log(x++ + 10);  // 15
// Evaluated as: (x++) + 10 = 5 + 10 (then x becomes 6)
console.log(x);  // 6

// Postfix has higher precedence than arithmetic
let a = 5;
let b = a++ * 2;
console.log(b);  // 10 ((a++) * 2 = 5 * 2)
console.log(a);  // 6

Prefix (Precedence 17)

let y = 5;
console.log(++y + 10);  // 16
// Evaluated as: (++y) + 10 = 6 + 10
console.log(y);  // 6

// Prefix vs postfix
let c = 5;
let d = 5;
console.log(c++ + ++d);  // 11
// Evaluated as: (c++) + (++d) = 5 + 6
console.log(c, d);  // 6 6

Unary Operators (Precedence 17)

Unary operators have high precedence.

// Unary before binary
console.log(-5 + 10);     // 5 ((-5) + 10)
console.log(+5 * 2);      // 10 ((+5) * 2)
console.log(!true && false);  // false ((!true) && false)

// typeof before arithmetic
console.log(typeof 5 + " value");  // "number value"
// Evaluated as: (typeof 5) + " value"

// Multiple unary operators
console.log(!!5);         // true
console.log(+-5);         // -5
console.log(-+5);         // -5
console.log(~~3.7);       // 3 (double bitwise NOT)

// Unary with comparison
console.log(!5 > 3);      // false
// Evaluated as: (!5) > 3 = false > 3 = false

Exponentiation (Precedence 16)

Exponentiation has higher precedence than multiplication.

// Exponentiation before multiplication
console.log(2 * 3 ** 2);  // 18
// Evaluated as: 2 * (3 ** 2) = 2 * 9 = 18

// NOT: (2 * 3) ** 2 = 6 ** 2 = 36

// Right-to-left associativity
console.log(2 ** 3 ** 2);  // 512
// Evaluated as: 2 ** (3 ** 2) = 2 ** 9 = 512

// NOT: (2 ** 3) ** 2 = 8 ** 2 = 64

// With parentheses
console.log((2 * 3) ** 2);  // 36
console.log((2 ** 3) ** 2);  // 64

Arithmetic Operators (Precedence 15, 14)

Multiplication, Division, Remainder (Precedence 15)

// *, /, % have same precedence (left-to-right)
console.log(12 / 2 * 3);    // 18 (not 2!)
// Evaluated as: (12 / 2) * 3 = 6 * 3 = 18

console.log(12 * 3 / 2);    // 18
// Evaluated as: (12 * 3) / 2 = 36 / 2 = 18

console.log(10 % 3 * 2);    // 2
// Evaluated as: (10 % 3) * 2 = 1 * 2 = 2

Addition, Subtraction (Precedence 14)

// +, - have lower precedence than *, /, %
console.log(2 + 3 * 4);     // 14
// Evaluated as: 2 + (3 * 4) = 2 + 12 = 14

console.log(10 - 2 * 3);    // 4
// Evaluated as: 10 - (2 * 3) = 10 - 6 = 4

// +, - have same precedence (left-to-right)
console.log(10 - 5 + 3);    // 8
// Evaluated as: (10 - 5) + 3 = 5 + 3 = 8

console.log(10 + 5 - 3);    // 12
// Evaluated as: (10 + 5) - 3 = 15 - 3 = 12

Complex Arithmetic

// Step-by-step evaluation
let result = 2 + 3 * 4 ** 2 / 2 - 1;

// Step 1: 4 ** 2 = 16        (highest precedence)
// Step 2: 3 * 16 = 48         (multiplication)
// Step 3: 48 / 2 = 24         (division)
// Step 4: 2 + 24 = 26         (addition)
// Step 5: 26 - 1 = 25         (subtraction)

console.log(result);  // 25

// With parentheses to change order
let result2 = ((2 + 3) * 4) ** 2 / (2 - 1);
// (5 * 4) ** 2 / 1 = 20 ** 2 / 1 = 400
console.log(result2);  // 400

Comparison Operators (Precedence 12, 11)

Relational (Precedence 12)

// Relational before equality
console.log(5 > 3 == true);  // true
// Evaluated as: (5 > 3) == true = true == true = true

// Arithmetic before relational
console.log(5 + 3 > 10);  // false
// Evaluated as: (5 + 3) > 10 = 8 > 10 = false

console.log(10 - 2 < 5 + 3);  // false
// Evaluated as: (10 - 2) < (5 + 3) = 8 < 8 = false

Equality (Precedence 11)

// Relational before equality
console.log(3 > 2 == 1 < 2);  // true
// Evaluated as: (3 > 2) == (1 < 2) = true == true = true

// All comparison before logical
console.log(5 > 3 && 10 < 20);  // true
// Evaluated as: (5 > 3) && (10 < 20) = true && true = true

Logical Operators (Precedence 7, 6)

Logical AND (Precedence 7)

// AND before OR
console.log(true || false && false);  // true
// Evaluated as: true || (false && false) = true || false = true

// NOT: (true || false) && false = true && false = false

// Comparison before AND
console.log(5 > 3 && 10 < 20);  // true
// Evaluated as: (5 > 3) && (10 < 20)

Logical OR (Precedence 6)

// AND before OR
console.log(false && true || true);  // true
// Evaluated as: (false && true) || true = false || true = true

console.log(true || false && true);  // true
// Evaluated as: true || (false && true) = true || false = true

// Multiple OR (left-to-right)
console.log(false || false || true);  // true
// Evaluated as: (false || false) || true = false || true = true

Complex Logical Expressions

// Common mistake
let x = 5;
let y = 10;
let z = 15;

// āŒ Wrong expectation
console.log(x < y || z);  // 15 (not boolean!)
// Evaluated as: (x < y) || z = true || 15 = true (returns true, short-circuits)
// Then: true (truthy value)

// Actually returns the first truthy value
console.log(false || 0 || "" || "hello");  // "hello"

// āœ… Correct comparison
console.log(x < y || x < z);  // true
// Evaluated as: (x < y) || (x < z) = true || true = true

Ternary Operator (Precedence 5)

The ternary operator has very low precedence.

// Most operations happen before ternary
console.log(5 + 3 > 10 ? "yes" : "no");  // "no"
// Evaluated as: ((5 + 3) > 10) ? "yes" : "no" = (8 > 10) ? ... = false ? ...

// Ternary in expressions
let result = 10 + (5 > 3 ? 2 : 0);  // 12
// Without parentheses, would be: (10 + 5) > 3 ? 2 : 0 (wrong!)

// Nested ternary (use parentheses!)
let grade = 85;
let letter = grade >= 90 ? "A" :
             grade >= 80 ? "B" :
             grade >= 70 ? "C" : "F";

// Better with parentheses for clarity
let letter2 = grade >= 90 ? "A" :
              (grade >= 80 ? "B" :
              (grade >= 70 ? "C" : "F"));

Assignment (Precedence 4)

Assignment has very low precedence and is right-to-left associative.

// All operations before assignment
let x = 5 + 3 * 2;  // 11
// Evaluated as: let x = (5 + (3 * 2))

// Right-to-left associativity
let a, b, c;
a = b = c = 5;
// Evaluated as: a = (b = (c = 5))
// First: c = 5 (returns 5)
// Then: b = 5 (returns 5)
// Finally: a = 5

// Assignment returns the assigned value
console.log(x = 10);  // 10
let y = (x = 20);
console.log(y);  // 20
console.log(x);  // 20

// Compound assignment
let z = 5;
z += 3 * 2;  // 11
// Evaluated as: z = z + (3 * 2) = 5 + 6 = 11

Comma Operator (Lowest Precedence)

The comma operator has the lowest precedence.

// Comma evaluates left to right, returns last
let x = (1, 2, 3);
console.log(x);  // 3

// Without parentheses (variable declaration, not comma operator)
let a = 1, b = 2, c = 3;
console.log(a, b, c);  // 1 2 3

// Everything happens before comma
let result = 1 + 2, 3 + 4;
console.log(result);  // 3 (not 7!)
// Evaluated as: (let result = (1 + 2)), (3 + 4)

// With parentheses to use comma operator
let result2 = (1 + 2, 3 + 4);
console.log(result2);  // 7 (returns last value)

Associativity

Associativity determines the order of evaluation when operators have the same precedence.

Left-to-Right (Most Operators)

// Arithmetic operators
console.log(10 - 5 - 2);  // 3
// Evaluated as: (10 - 5) - 2 = 5 - 2 = 3

console.log(20 / 4 / 2);  // 2.5
// Evaluated as: (20 / 4) / 2 = 5 / 2 = 2.5

// Comparison operators
console.log(5 < 10 < 20);  // true (but not what you might think!)
// Evaluated as: (5 < 10) < 20 = true < 20 = 1 < 20 = true

// Logical operators
console.log(true && false && true);  // false
// Evaluated as: (true && false) && true = false && true = false

Right-to-Left (Special Cases)

// Assignment
let a, b, c;
a = b = c = 5;
// Evaluated as: a = (b = (c = 5))

console.log(a, b, c);  // 5 5 5

// Exponentiation
console.log(2 ** 3 ** 2);  // 512
// Evaluated as: 2 ** (3 ** 2) = 2 ** 9 = 512

// Ternary
console.log(true ? 1 : false ? 2 : 3);  // 1
// Evaluated as: true ? 1 : (false ? 2 : 3)

// Unary operators (prefix)
console.log(++a++);  // SyntaxError (can't chain postfix and prefix)
console.log(!!true);  // true (right to left: !(!true))

Common Precedence Mistakes

Mistake 1: Comparison Chaining

// āŒ Wrong - doesn't work as expected
let x = 5;
console.log(3 < x < 7);  // true (but not because 3 < 5 < 7!)

// Why it's wrong:
// (3 < x) < 7
// (3 < 5) < 7
// true < 7
// 1 < 7
// true

// āœ… Correct - use logical AND
console.log(3 < x && x < 7);  // true (checks both conditions)

Mistake 2: Bitwise vs Logical

// āŒ Wrong - using bitwise instead of logical
console.log(5 & 3 == 1);  // false
// Evaluated as: 5 & (3 == 1) = 5 & false = 5 & 0 = 0 = false

// āœ… Correct - use parentheses or logical AND
console.log((5 & 3) == 1);  // true
console.log(5 && 3 == 1);   // false (different logic)

Mistake 3: typeof with Addition

// āŒ Unexpected
console.log(typeof 5 + 3);  // "number3"
// Evaluated as: (typeof 5) + 3 = "number" + 3 = "number3"

// āœ… Correct
console.log(typeof (5 + 3));  // "number"

Mistake 4: Increment with Addition

let x = 5;

// āŒ Confusing
console.log(++x + x++);  // 12
// Evaluated as: (++x) + (x++) = 6 + 6 (then x becomes 7)

// āœ… Clearer
x = 5;
let temp1 = ++x;  // 6
let temp2 = x++;  // 6 (then becomes 7)
console.log(temp1 + temp2);  // 12

Mistake 5: Logical OR with Addition

// āŒ Wrong - operator precedence misunderstanding
console.log(5 || 10 + 20);  // 5
// Evaluated as: 5 || (10 + 20) = 5 (short-circuits)

// What you might have wanted:
console.log((5 || 10) + 20);  // 25

Mistake 6: Assignment in Condition

let x = 5;

// āŒ Assignment (not comparison)
if (x = 10) {  // Always true (10 is truthy)
  console.log("This always runs");
}
console.log(x);  // 10 (x was changed!)

// āœ… Comparison
x = 5;
if (x === 10) {  // false
  console.log("This doesn't run");
}
console.log(x);  // 5 (x unchanged)

// āœ… Intentional assignment with extra parentheses
if ((x = getUser())) {  // Shows intent
  console.log("User exists");
}

Practical Examples

Example 1: Complex Expression Evaluation

// Evaluate step by step
let a = 2;
let b = 3;
let c = 4;

let result = a + b * c ** 2 / 2 - 1;

// Step-by-step with precedence:
// 1. c ** 2 = 16          (exponentiation - precedence 16)
// 2. b * 16 = 48          (multiplication - precedence 15)
// 3. 48 / 2 = 24          (division - precedence 15)
// 4. a + 24 = 26          (addition - precedence 14)
// 5. 26 - 1 = 25          (subtraction - precedence 14)

console.log(result);  // 25

// With parentheses for different result
let result2 = (a + b) * (c ** 2 / 2) - 1;
// (2 + 3) * (16 / 2) - 1 = 5 * 8 - 1 = 40 - 1 = 39
console.log(result2);  // 39

Example 2: Form Validation

function validateForm(username, password, email, age) {
  // Complex condition with proper precedence
  return username && 
         username.length >= 3 &&
         password &&
         password.length >= 8 &&
         email &&
         email.includes("@") &&
         age &&
         age >= 18;
  
  // Evaluation order:
  // 1. All property accesses (.length, .includes)
  // 2. All comparisons (>=, includes)
  // 3. Logical AND from left to right
}

console.log(validateForm("john", "password123", "john@example.com", 25));
// true

Example 3: Price Calculation

function calculateTotal(price, quantity, taxRate, discount) {
  // Without parentheses (wrong!)
  let wrong = price * quantity - discount + price * quantity * taxRate;
  
  // With parentheses (correct)
  let subtotal = price * quantity;
  let discountAmount = discount;
  let afterDiscount = subtotal - discountAmount;
  let tax = afterDiscount * taxRate;
  let total = afterDiscount + tax;
  
  return total;
  
  // Or in one line with parentheses:
  // return (price * quantity - discount) * (1 + taxRate);
}

console.log(calculateTotal(100, 2, 0.1, 20));
// 198 (correct with proper order)

Example 4: Access Control

function canAccess(user, resource) {
  // Complex permission check
  return user &&
         (user.isAdmin || 
          user.id === resource.ownerId ||
          user.permissions && 
          user.permissions.includes("read")) &&
         !resource.isDeleted &&
         (resource.isPublic || user.hasAccess);
  
  // Evaluation order:
  // 1. Property accesses (user.isAdmin, etc.)
  // 2. Method calls (.includes("read"))
  // 3. Comparisons (===)
  // 4. NOT (!)
  // 5. AND (&&) - higher precedence than OR
  // 6. OR (||)
}

Example 5: Complex Conditional

let score = 85;
let attendance = 95;
let extraCredit = 10;

// Complex grade calculation
let finalGrade = 
  score + 
  (attendance >= 90 ? 5 : 0) + 
  (extraCredit > 0 ? Math.min(extraCredit, 10) : 0);

// Evaluation order:
// 1. attendance >= 90 (comparison)
// 2. ternary for attendance bonus
// 3. extraCredit > 0 (comparison)
// 4. Math.min() (function call)
// 5. ternary for extra credit
// 6. Addition operations
// 7. Assignment

console.log(finalGrade);  // 100

Best Practices

1. Use Parentheses for Clarity

// āŒ Hard to understand
let result = a + b * c / d - e;

// āœ… Clear intention
let result = a + ((b * c) / d) - e;

// āœ… Even clearer - break into steps
let product = b * c;
let quotient = product / d;
let result = a + quotient - e;

2. Break Complex Expressions

// āŒ Too complex
if (user && user.isActive && (user.isAdmin || user.permissions.includes("write")) && !resource.isLocked) { }

// āœ… Break it down
let userExists = user !== null;
let userActive = user && user.isActive;
let hasWriteAccess = user && (user.isAdmin || user.permissions.includes("write"));
let resourceAvailable = resource && !resource.isLocked;

if (userExists && userActive && hasWriteAccess && resourceAvailable) { }

3. Avoid Mixing Bitwise and Logical

// āŒ Confusing
if (flags & PERMISSION_READ && user.isActive | 0) { }

// āœ… Clear separation
if ((flags & PERMISSION_READ) !== 0 && user.isActive) { }

4. Be Careful with typeof

// āŒ Wrong
if (typeof value === "number" && value > 0) { }
// If value is undefined, typeof returns "string", then "string" && value causes error

// āœ… Correct (typeof has high precedence)
if (typeof value === "number" && value > 0) { }  // This is actually correct!

// āŒ Actually wrong case:
if (typeof value && value > 0) { }
// Evaluates as: (typeof value) && (value > 0)
// typeof always returns a truthy string

// āœ… Better
if (typeof value === "number" && value > 0) { }

5. Parenthesize Ternaries in Expressions

// āŒ Unclear
let price = basePrice + isDiscount ? 0 : tax;
// Evaluates as: (basePrice + isDiscount) ? 0 : tax

// āœ… Clear
let price = basePrice + (isDiscount ? 0 : tax);

6. Use Consistent Style

// āŒ Inconsistent
let a = x+y*z;
let b = x + y*z;
let c = x + (y * z);

// āœ… Consistent - always use spaces and parentheses for clarity
let a = x + (y * z);
let b = x + (y * z);
let c = x + (y * z);

Debugging Precedence Issues

How to Debug Complex Expressions

// Original expression
let result = 2 + 3 * 4 ** 2 / 2 - 1;

// Method 1: Add console.logs for each step
console.log("Step 1:", 4 ** 2);           // 16
console.log("Step 2:", 3 * 16);           // 48
console.log("Step 3:", 48 / 2);           // 24
console.log("Step 4:", 2 + 24);           // 26
console.log("Step 5:", 26 - 1);           // 25

// Method 2: Break into named steps
let step1 = 4 ** 2;        // 16
let step2 = 3 * step1;     // 48
let step3 = step2 / 2;     // 24
let step4 = 2 + step3;     // 26
let step5 = step4 - 1;     // 25

// Method 3: Add explicit parentheses
let result2 = 2 + (((3 * (4 ** 2)) / 2) - 1);

Common Debugging Patterns

// Check if your understanding is correct
function testPrecedence() {
  // Test 1: Arithmetic
  console.assert(2 + 3 * 4 === 14, "Multiplication before addition");
  
  // Test 2: Comparison
  console.assert(5 + 3 > 10 === false, "Addition before comparison");
  
  // Test 3: Logical
  console.assert(true || false && false === true, "AND before OR");
  
  // Test 4: Assignment
  let x, y;
  console.assert((x = y = 5) === 5, "Assignment is right-to-left");
  
  console.log("All precedence tests passed!");
}

testPrecedence();

Quick Reference Guide

Precedence Memory Aid

From Highest to Lowest:

Grouping:        ( )
Member:          . []
New/Call:        new fn()
Postfix:         x++
Unary:           !x ++x typeof
Power:           **
Multiply:        * / %
Add:             + -
Shift:           << >>
Compare:         < > <= >= in instanceof
Equality:        == === != !==
Bitwise AND:     &
Bitwise XOR:     ^
Bitwise OR:      |
Logical AND:     &&
Logical OR:      ||
Ternary:         ? :
Assignment:      = += -=
Comma:           ,

When to Use Parentheses

Always use parentheses when:

  1. Mixing arithmetic and logical operators
  2. Using bitwise with other operators
  3. Ternary operator in expressions
  4. Assignment in conditions (intentional)
  5. Any expression that might be unclear
// Always parenthesize these:
if ((user = getUser())) { }              // Intentional assignment
let x = (condition ? a : b) + c;         // Ternary in expression
let y = (a && b) || (c && d);            // Mixed logical
let z = (flags & MASK) !== 0;            // Bitwise comparison

Practice Exercises

Create a file called precedence-practice.js:

// Operator Precedence Practice

// Exercise 1: Predict the output
console.log(2 + 3 * 4);
console.log(10 - 2 * 3);
console.log((2 + 3) * 4);
console.log(2 ** 3 ** 2);
console.log((2 ** 3) ** 2);

// Exercise 2: Fix the expression
// This should check if x is between 10 and 20
let x = 15;
// āŒ Wrong: console.log(10 < x < 20);
// āœ… Fix it:

// Exercise 3: Calculate correct result
// Price: $100, Quantity: 3, Tax: 8%, Discount: $20
// Calculate: (price * quantity - discount) * (1 + tax)
// Write with proper parentheses:

// Exercise 4: Evaluate step by step
let result = 5 + 3 * 2 ** 2 / 4 - 1;
// Show each step:
// Step 1: ...
// Step 2: ...
// Final: ...

// Exercise 5: Rewrite for clarity
// āŒ Hard to read:
let complex = a + b * c / d - e && f || g;

// āœ… Rewrite with parentheses and/or break into steps:

// Exercise 6: Fix the bug
let score = 80;
let grade = score >= 90 ? "A" : 
            score >= 80 ? "B" :
            score >= 70 ? "C" : "F";
// This works, but how would you make it clearer with parentheses?

// Exercise 7: Debug this
let value = 5;
console.log(typeof value === "number" && value > 0);
// Does this work? Why or why not?

// Exercise 8: Logical precedence
console.log(true || false && false);
console.log((true || false) && false);
// Why are these different?

Summary

Congratulations! šŸŽ‰ You've completed the comprehensive study of JavaScript operators, including precedence and associativity.

Key Takeaways

āœ… Precedence Hierarchy:

  • Grouping () - Highest
  • Member access . []
  • Unary ! ++ typeof
  • Exponentiation **
  • Arithmetic * / % → + -
  • Comparison < > → == ===
  • Logical && → ||
  • Ternary ? :
  • Assignment =
  • Comma , - Lowest

āœ… Associativity:

  • Left-to-right: Most operators
  • Right-to-left: Assignment, exponentiation, ternary

āœ… Best Practices:

  • Use parentheses for clarity
  • Break complex expressions into steps
  • Name intermediate values
  • Be consistent with style
  • Test your understanding

āœ… Common Mistakes:

  • Comparison chaining: 3 < x < 7 āŒ
  • typeof with addition
  • Bitwise vs logical operators
  • Assignment in conditions

āœ… Debugging Tips:

  • Add console.logs for each step
  • Break into named variables
  • Add explicit parentheses
  • Write test assertions

What's Next?

Excellent work! šŸŽ‰ You've mastered all the JavaScript operators and understand how they work together.

You're now ready to move on to Control Flow where you'll learn:

  • Conditional Statements (if/else, switch)
  • Loops (for, while, do-while)
  • Break and Continue
  • Error Handling (try/catch)

These concepts will use the operators you've learned to control program flow!