Part 3: Operators and Expressions

Combining Values to Produce Results


Expressions and Statements

Before diving into operators, let's clarify the difference between expressions and statements.
javascript
// Expressions produce values 5 + 3 // 8 'Hello' + ' World' // 'Hello World' x > 10 ? 'big' : 'small' // produces a value // Statements perform actions let x = 10; // declaration statement if (x > 5) { } // control flow statement for (let i = 0; i < 10; i++) { } // loop statement // Expression statements - expressions used as statements console.log('hello'); // function call expression as statement x++; // increment expression as statement

Arithmetic Operators

Basic Arithmetic

javascript
// Addition console.log(5 + 3); // 8 console.log('Hello' + ' ' + 'World'); // 'Hello World' (concatenation) // Subtraction console.log(10 - 4); // 6 // Multiplication console.log(6 * 7); // 42 // Division console.log(20 / 4); // 5 console.log(7 / 2); // 3.5 (not integer division!) // Modulo (remainder) console.log(10 % 3); // 1 console.log(17 % 5); // 2 console.log(-10 % 3); // -1 (sign follows dividend) // Exponentiation console.log(2 ** 10); // 1024 console.log(9 ** 0.5); // 3 (square root)

Unary Operators

javascript
// Unary plus - converts to number console.log(+'42'); // 42 console.log(+true); // 1 console.log(+'hello'); // NaN // Unary minus - negates console.log(-5); // -5 console.log(-(-5)); // 5 // Increment and Decrement let x = 5; console.log(x++); // 5 (returns, then increments) console.log(x); // 6 let y = 5; console.log(++y); // 6 (increments, then returns) console.log(y); // 6 // Same for decrement let z = 5; console.log(z--); // 5 console.log(--z); // 3

Assignment Operators

javascript
let x = 10; // Compound assignment x += 5; // x = x + 5; → 15 x -= 3; // x = x - 3; → 12 x *= 2; // x = x * 2; → 24 x /= 4; // x = x / 4; → 6 x %= 4; // x = x % 4; → 2 x **= 3; // x = x ** 3; → 8 // Chained assignment (right to left) let a, b, c; a = b = c = 10; console.log(a, b, c); // 10 10 10

Comparison Operators

Equality Operators

javascript
// Strict equality (===) - no type coercion console.log(5 === 5); // true console.log(5 === '5'); // false console.log(null === undefined); // false // Strict inequality (!==) console.log(5 !== '5'); // true console.log(5 !== 5); // false // Loose equality (==) - allows type coercion console.log(5 == '5'); // true (string converted to number) console.log(0 == false); // true console.log(null == undefined); // true console.log('' == 0); // true console.log([] == false); // true (empty array → '' → 0) // Loose inequality (!=) console.log(5 != '5'); // false

Relational Operators

javascript
// Greater than / Less than console.log(5 > 3); // true console.log(5 < 3); // false // Greater than or equal / Less than or equal console.log(5 >= 5); // true console.log(5 <= 4); // false // String comparison (lexicographic) console.log('apple' < 'banana'); // true console.log('Apple' < 'apple'); // true (uppercase comes first) console.log('2' > '10'); // true (string comparison!) console.log(2 > 10); // false (number comparison)

Special Comparisons

javascript
// NaN is not equal to anything, including itself console.log(NaN === NaN); // false console.log(Number.isNaN(NaN)); // true // Object comparison (by reference) const obj1 = { value: 1 }; const obj2 = { value: 1 }; const obj3 = obj1; console.log(obj1 === obj2); // false (different objects) console.log(obj1 === obj3); // true (same reference) // Object.is for more precise comparison console.log(Object.is(NaN, NaN)); // true console.log(Object.is(0, -0)); // false console.log(0 === -0); // true

Logical Operators

Basic Logical Operators

javascript
// AND (&&) console.log(true && true); // true console.log(true && false); // false console.log(false && true); // false console.log(false && false); // false // OR (||) console.log(true || true); // true console.log(true || false); // true console.log(false || true); // true console.log(false || false); // false // NOT (!) console.log(!true); // false console.log(!false); // true console.log(!!0); // false (double NOT for boolean conversion) console.log(!!'hello'); // true

Short-Circuit Evaluation

javascript
// AND short-circuits on first falsy value console.log(false && 'hello'); // false console.log(true && 'hello'); // 'hello' console.log('a' && 'b' && 'c'); // 'c' (last value if all truthy) console.log('a' && 0 && 'c'); // 0 (first falsy value) // OR short-circuits on first truthy value console.log(true || 'hello'); // true console.log(false || 'hello'); // 'hello' console.log(null || 0 || 'hi'); // 'hi' (first truthy value) console.log(null || 0 || ''); // '' (last value if all falsy)

Practical Uses of Short-Circuit

javascript
// Default values (traditional way) function greet(name) { name = name || 'Guest'; console.log(`Hello, ${name}!`); } greet(); // 'Hello, Guest!' greet('Alice'); // 'Hello, Alice!' // Conditional execution const isLoggedIn = true; isLoggedIn && console.log('Welcome back!'); // Guard against null/undefined const user = null; const name = user && user.name; // undefined (doesn't throw) // Object property access const config = {}; const timeout = config.settings && config.settings.timeout;

Nullish Coalescing (??)

javascript
// ?? returns right side only for null/undefined console.log(null ?? 'default'); // 'default' console.log(undefined ?? 'default'); // 'default' console.log(0 ?? 'default'); // 0 (0 is not nullish) console.log('' ?? 'default'); // '' (empty string is not nullish) console.log(false ?? 'default'); // false // Comparison with || console.log(0 || 'default'); // 'default' (0 is falsy) console.log(0 ?? 'default'); // 0 (0 is not nullish) // Practical use function getConfig(options) { const timeout = options.timeout ?? 5000; // Default only if null/undefined const retries = options.retries ?? 3; return { timeout, retries }; } getConfig({ timeout: 0, retries: 0 }); // { timeout: 0, retries: 0 }

The Conditional (Ternary) Operator

javascript
// Syntax: condition ? valueIfTrue : valueIfFalse const age = 20; const status = age >= 18 ? 'adult' : 'minor'; console.log(status); // 'adult' // Nested ternary (use sparingly) const score = 85; const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : score >= 60 ? 'D' : 'F'; console.log(grade); // 'B' // In template literals const count = 5; console.log(`You have ${count} item${count === 1 ? '' : 's'}`); // 'You have 5 items' // For conditional assignment const config = { debug: process.env.NODE_ENV !== 'production' ? true : false }; // Simplified (when returning boolean) const config2 = { debug: process.env.NODE_ENV !== 'production' };

Bitwise Operators

Bitwise operators work on 32-bit integers.

Basic Bitwise Operators

javascript
// AND (&) console.log(5 & 3); // 1 // 5 = 101 // 3 = 011 // & = 001 = 1 // OR (|) console.log(5 | 3); // 7 // 5 = 101 // 3 = 011 // | = 111 = 7 // XOR (^) console.log(5 ^ 3); // 6 // 5 = 101 // 3 = 011 // ^ = 110 = 6 // NOT (~) console.log(~5); // -6 // ~n = -(n + 1) // Left shift (<<) console.log(5 << 1); // 10 // 5 = 101 // << = 1010 = 10 (multiply by 2) // Right shift (>>) console.log(5 >> 1); // 2 // 5 = 101 // >> = 10 = 2 (divide by 2, floor) // Unsigned right shift (>>>) console.log(-1 >>> 0); // 4294967295

Practical Bitwise Uses

javascript
// Check if number is even/odd const isEven = n => (n & 1) === 0; console.log(isEven(4)); // true console.log(isEven(7)); // false // Swap values without temp variable let a = 5, b = 3; a ^= b; b ^= a; a ^= b; console.log(a, b); // 3 5 // Multiply/divide by powers of 2 console.log(5 << 2); // 20 (5 * 4) console.log(20 >> 2); // 5 (20 / 4) // Floor a number console.log(~~3.7); // 3 console.log(3.7 | 0); // 3 // Check flags const READ = 1; // 001 const WRITE = 2; // 010 const EXECUTE = 4; // 100 let permissions = READ | WRITE; // 011 // Check permission console.log((permissions & READ) !== 0); // true console.log((permissions & EXECUTE) !== 0); // false // Add permission permissions |= EXECUTE; // 111 // Remove permission permissions &= ~WRITE; // 101

Optional Chaining (?.)

javascript
const user = { name: 'Alice', address: { city: 'Boston' } }; // Without optional chaining const zipCode = user.address && user.address.zipCode; // With optional chaining const zipCode2 = user.address?.zipCode; // undefined (doesn't throw) // Deeply nested access const street = user?.address?.street?.name; // undefined // With arrays const arr = null; const first = arr?.[0]; // undefined // With function calls const user2 = { getName: () => 'Alice' }; console.log(user2.getName?.()); // 'Alice' console.log(user2.getAge?.()); // undefined // Combined with nullish coalescing const city = user?.address?.city ?? 'Unknown'; console.log(city); // 'Boston'

The typeof Operator

javascript
console.log(typeof undefined); // 'undefined' console.log(typeof null); // 'object' (bug) console.log(typeof true); // 'boolean' console.log(typeof 42); // 'number' console.log(typeof 42n); // 'bigint' console.log(typeof 'hello'); // 'string' console.log(typeof Symbol()); // 'symbol' console.log(typeof {}); // 'object' console.log(typeof []); // 'object' console.log(typeof function(){}); // 'function' // Safe undefined check if (typeof myVar === 'undefined') { // myVar doesn't exist or is undefined } // Type checking pattern function process(value) { switch (typeof value) { case 'string': return value.toUpperCase(); case 'number': return value * 2; case 'boolean': return !value; default: return value; } }

The instanceof Operator

javascript
// Check if object is instance of constructor const arr = [1, 2, 3]; console.log(arr instanceof Array); // true console.log(arr instanceof Object); // true (arrays are objects) const date = new Date(); console.log(date instanceof Date); // true // Custom classes class Animal {} class Dog extends Animal {} const dog = new Dog(); console.log(dog instanceof Dog); // true console.log(dog instanceof Animal); // true console.log(dog instanceof Object); // true // Primitives console.log('hello' instanceof String); // false console.log(new String('hello') instanceof String); // true

The in Operator

javascript
// Check if property exists in object const obj = { name: 'Alice', age: 30 }; console.log('name' in obj); // true console.log('email' in obj); // false console.log('toString' in obj); // true (inherited) // Check array indices const arr = [1, 2, 3]; console.log(0 in arr); // true console.log(5 in arr); // false console.log('length' in arr); // true

Operator Precedence

Operators have different precedence levels. Higher precedence operators execute first.
Precedence (highest to lowest): ┌────┬──────────────────────────────────────────┐ │ 1 │ () grouping │ ├────┼──────────────────────────────────────────┤ │ 2 │ . [] () ?. member access, call │ ├────┼──────────────────────────────────────────┤ │ 3 │ new (with args) │ ├────┼──────────────────────────────────────────┤ │ 4 │ ++ -- (postfix) │ ├────┼──────────────────────────────────────────┤ │ 5 │ ! ~ + - ++ -- typeof void delete (unary) │ ├────┼──────────────────────────────────────────┤ │ 6 │ ** │ ├────┼──────────────────────────────────────────┤ │ 7 │ * / % │ ├────┼──────────────────────────────────────────┤ │ 8 │ + - │ ├────┼──────────────────────────────────────────┤ │ 9 │ << >> >>> │ ├────┼──────────────────────────────────────────┤ │ 10 │ < <= > >= in instanceof │ ├────┼──────────────────────────────────────────┤ │ 11 │ == != === !== │ ├────┼──────────────────────────────────────────┤ │ 12 │ & │ ├────┼──────────────────────────────────────────┤ │ 13 │ ^ │ ├────┼──────────────────────────────────────────┤ │ 14 │ | │ ├────┼──────────────────────────────────────────┤ │ 15 │ && │ ├────┼──────────────────────────────────────────┤ │ 16 │ || │ ├────┼──────────────────────────────────────────┤ │ 17 │ ?? │ ├────┼──────────────────────────────────────────┤ │ 18 │ ?: (ternary) │ ├────┼──────────────────────────────────────────┤ │ 19 │ = += -= *= etc. (assignment) │ ├────┼──────────────────────────────────────────┤ │ 20 │ , (comma) │ └────┴──────────────────────────────────────────┘
javascript
// Precedence examples console.log(2 + 3 * 4); // 14 (not 20) console.log((2 + 3) * 4); // 20 console.log(true || false && false); // true // && has higher precedence: true || (false && false) console.log(5 > 3 === true); // true // > evaluates first: (5 > 3) === true // Use parentheses for clarity const result = (a > b) && (c < d); const value = condition ? (a + b) : (c + d);

Summary

Arithmetic operators:
  • +, -, *, /, %, ** for math operations
  • ++, -- for increment/decrement
  • +=, -=, etc. for compound assignment
Comparison operators:
  • Always prefer === and !== over == and !=
  • Be careful with object comparison (by reference)
  • Use Object.is() for special cases like NaN
Logical operators:
  • &&, ||, ! for logical operations
  • Short-circuit evaluation enables patterns like default values
  • ?? is safer than || for default values (nullish only)
Other operators:
  • ?. for safe property access
  • typeof for type checking
  • instanceof for constructor checking
  • in for property existence

Questions to Think About

  1. Why should you prefer === over ==?
Loose equality (==) performs type coercion, which can lead to unexpected results like 0 == '' being true. Strict equality (===) requires both type and value to match, making your code more predictable and easier to debug.
  1. When would you use ?? instead of ||?
Use ?? when you want to provide a default only for null or undefined, but want to keep other falsy values like 0, '', or false. Use || when any falsy value should trigger the default.
  1. How does short-circuit evaluation work?
&& returns the first falsy value or the last value if all are truthy. || returns the first truthy value or the last value if all are falsy. Expressions after the first decisive value are never evaluated.
  1. What are practical uses for bitwise operators?
Permission flags, checking even/odd numbers, fast multiplication/division by powers of 2, converting floats to integers, and low-level data manipulation.
  1. Why does operator precedence matter?
Without understanding precedence, expressions like 2 + 3 * 4 might seem to produce 20 instead of 14. Use parentheses to make intent clear and avoid bugs.

Next: Part 4 - Control Flow, where we explore conditionals, loops, switch statements, and flow control.
All Blogs
Tags:javascriptoperatorsexpressionsbitwiseprecedence