// Simple assignmentlet x = 10;// Compound assignmentsx += 5; // x = x + 5; x is now 15x -= 3; // x = x - 3; x is now 12x *= 2; // x = x * 2; x is now 24x /= 4; // x = x / 4; x is now 6x %= 5; // x = x % 5; x is now 1x **= 3; // x = x ** 3; x is now 1// String concatenation with +=let str = "Hello";str += " World"; // str is "Hello World"// Multiple assignment (right-to-left)let a, b, c;a = b = c = 5; // All are 5console.log(a, b, c); // 5 5 5// Assignment returns valuelet y = (x = 10); // x is 10, y is 10console.log(x, y); // 10 10// Destructuring assignmentlet [p, q] = [1, 2];console.log(p, q); // 1 2let {name, age} = {name: "John", age: 30};console.log(name, age); // "John" 30// Compound assignment with side effectslet arr = [10, 20, 30];let i = 0;arr[i++] += 5; // arr[0] becomes 15, then i incrementsconsole.log(arr[0], i); // 15 1// Swapping with destructuringlet m = 1, n = 2;[m, n] = [n, m]; // Swapconsole.log(m, n); // 2 1
3. Comparison Operators (==, ===, !=, !==) and Equality Rules
Warning: Always use === and !== (strict equality) to avoid unexpected
type coercion bugs. Use == only when you specifically need type coercion.
4. Logical Operators (&&, ||, !) and Short-circuit Evaluation
Operator
Name
Returns
Short-circuits
Use Case
&&
Logical AND
First falsy value or last value
✓ If left is falsy
Both conditions must be true
||
Logical OR
First truthy value or last value
✓ If left is truthy
At least one condition must be true
!
Logical NOT
Boolean (inverted)
✗ No
Inverts truthiness
!!
Double NOT
Boolean conversion
✗ No
Convert to boolean explicitly
Expression
Result
Explanation
true && true
true
Both truthy → returns last value
true && false
false
Right is falsy → returns false
false && true
false
Short-circuits at false (left)
5 && "hello"
"hello"
Both truthy → returns last
0 && "hello"
0
First falsy → returns 0
true || false
true
Short-circuits at first truthy
false || true
true
Returns first truthy value
false || false
false
Both falsy → returns last
5 || "hello"
5
First truthy → short-circuits
0 || "hello"
"hello"
First falsy, returns second
!true
false
Inverts boolean
!0
true
0 is falsy, inverted to true
!!"hello"
true
Convert to boolean: truthy
Example: Logical operators and short-circuit evaluation
// Logical AND (&&) - returns first falsy or last valueconsole.log(true && true); // trueconsole.log(true && false); // falseconsole.log(5 && 10); // 10 (both truthy, returns last)console.log(0 && 10); // 0 (first falsy)console.log(null && "hello"); // null (first falsy)// Logical OR (||) - returns first truthy or last valueconsole.log(false || true); // trueconsole.log(false || false); // false (last value)console.log(5 || 10); // 5 (first truthy)console.log(0 || 10); // 10 (first falsy, returns second)console.log(null || "default"); // "default" (first falsy)// Logical NOT (!)console.log(!true); // falseconsole.log(!false); // trueconsole.log(!0); // true (0 is falsy)console.log(!""); // true ("" is falsy)console.log(!"hello"); // false ("hello" is truthy)// Double NOT (!!) - convert to booleanconsole.log(!!"hello"); // trueconsole.log(!!0); // falseconsole.log(!!""); // falseconsole.log(!!{}); // true (objects are truthy)// Short-circuit evaluation - practical uses// 1. Default values (before ?? was added)let username = input || "Guest"; // If input is falsy, use "Guest"// 2. Conditional executionisLoggedIn && showDashboard(); // Execute if truthyhasError || showSuccessMessage(); // Execute if falsy// 3. Guard clausesfunction processUser(user) { user && user.profile && console.log(user.profile.name); // Only accesses nested property if all are truthy}// 4. Avoiding function callslet result = expensiveCheck() || cachedValue;// If expensiveCheck() is truthy, cachedValue never evaluated// Short-circuit prevents errorslet obj = null;let value = obj && obj.property; // undefined (doesn't throw)// Without short-circuit: obj.property would throw error// Combining operatorslet access = isAdmin || (isPremium && hasPermission);console.log(true || (false && error())); // true, error() not called// Falsy values: false, 0, "", null, undefined, NaNconsole.log(false || 0 || "" || null || undefined || NaN || "found");// "found" (first truthy)
Note: Logical operators return the actual value (not just boolean). Short-circuit evaluation
stops at first definitive result, useful for default values and conditional execution.
// Logical OR patternx = x || defaultValue;if (!x) x = defaultValue;// Logical AND patternx = x && newValue;if (x) x = newValue;// Nullish patternx = x ?? defaultValue;if (x == null) x = defaultValue;
With ES2021:
// Logical OR assignmentx ||= defaultValue;// Logical AND assignmentx &&= newValue;// Nullish assignmentx ??= defaultValue;
Example: Logical assignment operators
// ||= Logical OR Assignment// Assigns if left side is falsylet a = 0;a ||= 10; // a is 10 (0 is falsy)let b = 5;b ||= 10; // b is still 5 (5 is truthy)let c = "";c ||= "default"; // c is "default" ("" is falsy)// &&= Logical AND Assignment// Assigns if left side is truthylet x = 5;x &&= 10; // x is 10 (5 is truthy)let y = 0;y &&= 10; // y is still 0 (0 is falsy, no assignment)let z = null;z &&= 10; // z is still null (null is falsy)// ??= Nullish Assignment// Assigns only if null or undefinedlet p = 0;p ??= 10; // p is still 0 (0 is not null/undefined)let q = null;q ??= 10; // q is 10 (null)let r = undefined;r ??= 10; // r is 10 (undefined)let s = false;s ??= true; // s is still false (false is not null/undefined)// Practical use cases// 1. Object property defaults with ??=const config = { timeout: 0, // 0 is valid retry: null // null should be replaced};config.timeout ??= 3000; // Still 0 (not null/undefined)config.retry ??= 3; // Now 3 (was null)config.newProp ??= "default"; // "default" (was undefined)console.log(config);// { timeout: 0, retry: 3, newProp: "default" }// 2. Accumulation with &&=let total = 100;let applyDiscount = true;total &&= total * 0.9; // Apply 10% discount if total existsconsole.log(total); // 90let nullTotal = null;nullTotal &&= nullTotal * 0.9; // No operation (nullTotal is falsy)console.log(nullTotal); // null (unchanged)// 3. Cache pattern with ||=let cache = {};function getData(key) { // Set cache if not already set cache[key] ||= expensiveOperation(key); return cache[key];}function expensiveOperation(key) { console.log("Computing..."); return key * 2;}console.log(getData(5)); // "Computing..." then 10console.log(getData(5)); // 10 (from cache, no computing)// 4. Updating objects conditionallyconst user = { name: "Alice", age: null, status: undefined};user.name ||= "Anonymous"; // Still "Alice" (truthy)user.age ??= 18; // Now 18 (was null)user.status ??= "active"; // Now "active" (was undefined)// 5. Short-circuit: right side not evaluated if condition not metlet count = 0;let getValue = () => { count++; return 100; };let x1 = 5;x1 ||= getValue(); // getValue() NOT called (x1 is truthy)console.log(count); // 0let x2 = 0;x2 ||= getValue(); // getValue() IS called (x2 is falsy)console.log(count); // 1
Note: Logical assignment operators combine logical operations with assignment, providing
cleaner syntax and short-circuit evaluation (right side only evaluated when assignment occurs).
Section 4 Summary
Arithmetic operators include +, -, *, /, %, ** (exponentiation);
+ concatenates strings if either operand is string
Assignment operators support compound forms (+=, -=, *=, etc.) for concise
update operations
Use strict equality (===, !==) to avoid type coercion bugs; loose equality
(==) performs type conversion
Logical operators (&&, ||, !) short-circuit and return actual values, not
just booleans; useful for defaults and guards
Bitwise operators work on 32-bit integers; useful for flags, permissions,
and fast math operations
Optional chaining (?.) safely accesses nested properties; nullish coalescing (??) provides defaults only for null/undefined
Logical assignment (||=, &&=, ??=) combines logic with assignment;
short-circuits when assignment unnecessary