Welcome back! 👋 In the previous lesson, you learned about arithmetic operators. Now, let's explore assignment operators - operators that assign values to variables and provide shortcuts for common operations.
Assignment operators are fundamental to programming. They let you store values, update variables, and write more concise code. Let's master them!
What are Assignment Operators?
Assignment operators assign values to JavaScript variables. The most basic assignment operator is =, which assigns the value on the right to the variable on the left.
let x = 10; // Assigns 10 to x
let name = "John"; // Assigns "John" to name
let isActive = true; // Assigns true to isActiveBut JavaScript also provides compound assignment operators that combine assignment with another operation, making your code more concise and readable.
Simple Assignment Operator (=)
The simple assignment operator assigns the value of the right operand to the left operand.
Syntax
variable = valueExamples
// Basic assignment
let x = 10;
let name = "Mihir";
let isStudent = false;
console.log(x); // 10
console.log(name); // "Mihir"
console.log(isStudent); // false
// Assigning expressions
let a = 5;
let b = a + 10; // b = 15
let c = a * 2; // c = 10
// Reassignment
let count = 0;
count = 5; // count is now 5
count = count + 1; // count is now 6Assignment Returns a Value
Important: Assignment is an expression that returns the assigned value.
let x = 10;
console.log(x = 20); // 20 (logs 20, and x becomes 20)
console.log(x); // 20
// This allows chaining assignments
let a, b, c;
a = b = c = 5; // All get value 5
console.log(a, b, c); // 5 5 5
// How it works (right to left):
// c = 5 (c becomes 5, returns 5)
// b = 5 (b becomes 5, returns 5)
// a = 5 (a becomes 5, returns 5)Assignment in Conditions (Be Careful!)
// ❌ Common mistake - assignment instead of comparison
let x = 10;
if (x = 5) { // This assigns 5 to x, doesn't compare!
console.log("This always runs"); // Always runs because 5 is truthy
}
console.log(x); // 5 (x was changed!)
// ✅ Correct - comparison
let y = 10;
if (y === 5) { // This compares
console.log("This doesn't run"); // Doesn't run
}
console.log(y); // 10 (y unchanged)
// ✅ Intentional assignment in condition (rare, but valid)
let user = null;
if (user = getUser()) { // Assigns and checks if truthy
console.log(`User found: ${user.name}`);
}Compound Assignment Operators
Compound assignment operators combine an arithmetic or logical operation with assignment, providing a shorthand notation.
General Pattern:
x = x + 5; // Long form
x += 5; // Short form (compound assignment)Let's explore each one!
Addition Assignment (+=)
Adds the right operand to the left operand and assigns the result to the left operand.
Syntax
x += y
// Equivalent to: x = x + yExamples with Numbers
// Basic usage
let count = 10;
count += 5;
console.log(count); // 15 (same as: count = count + 5)
// Multiple operations
let total = 100;
total += 20; // 120
total += 30; // 150
total += 50; // 200
console.log(total); // 200
// With negative numbers
let balance = 1000;
balance += -50; // Same as balance -= 50
console.log(balance); // 950
// With expressions
let x = 10;
x += (5 * 2); // x = x + (5 * 2) = x + 10
console.log(x); // 20Examples with Strings (Concatenation)
// String concatenation
let message = "Hello";
message += " World";
console.log(message); // "Hello World"
// Building strings incrementally
let html = "<div>";
html += "<h1>Title</h1>";
html += "<p>Content</p>";
html += "</div>";
console.log(html);
// "<div><h1>Title</h1><p>Content</p></div>"
// Adding to greeting
let greeting = "Hi";
greeting += ", ";
greeting += "how are you?";
console.log(greeting); // "Hi, how are you?"Practical Examples
// Accumulating total in a loop
let numbers = [10, 20, 30, 40, 50];
let sum = 0;
for (let num of numbers) {
sum += num;
}
console.log(sum); // 150
// Building a list
let shoppingList = "Shopping List:\n";
shoppingList += "- Milk\n";
shoppingList += "- Bread\n";
shoppingList += "- Eggs\n";
console.log(shoppingList);
// Counter in event handlers
let clickCount = 0;
function handleClick() {
clickCount += 1;
console.log(`Clicked ${clickCount} times`);
}
// Score accumulation
let score = 0;
score += 10; // Level 1 completed
score += 25; // Level 2 completed
score += 50; // Level 3 completed
console.log(`Total Score: ${score}`); // Total Score: 85Subtraction Assignment (-=)
Subtracts the right operand from the left operand and assigns the result to the left operand.
Syntax
x -= y
// Equivalent to: x = x - yExamples
// Basic usage
let count = 100;
count -= 25;
console.log(count); // 75 (same as: count = count - 25)
// Multiple operations
let stock = 500;
stock -= 50; // 450
stock -= 100; // 350
stock -= 75; // 275
console.log(stock); // 275
// With negative numbers
let temperature = 20;
temperature -= -5; // Same as temperature += 5
console.log(temperature); // 25
// With expressions
let x = 100;
x -= (10 * 2); // x = x - (10 * 2) = x - 20
console.log(x); // 80Practical Examples
// Decreasing inventory
let inventory = 100;
function sellItem(quantity) {
inventory -= quantity;
console.log(`Sold ${quantity}. Remaining: ${inventory}`);
}
sellItem(10); // Sold 10. Remaining: 90
sellItem(25); // Sold 25. Remaining: 65
// Lives in a game
let lives = 3;
lives -= 1; // Lost a life
console.log(`Lives remaining: ${lives}`); // Lives remaining: 2
// Wallet balance
let wallet = 1000;
wallet -= 50; // Coffee
wallet -= 120; // Lunch
wallet -= 30; // Taxi
console.log(`Remaining balance: $${wallet}`); // Remaining balance: $800
// Countdown timer
let timeLeft = 60;
function tick() {
timeLeft -= 1;
console.log(`Time left: ${timeLeft}s`);
if (timeLeft === 0) {
console.log("Time's up!");
}
}Multiplication Assignment (*=)
Multiplies the left operand by the right operand and assigns the result to the left operand.
Syntax
x *= y
// Equivalent to: x = x * yExamples
// Basic usage
let count = 5;
count *= 3;
console.log(count); // 15 (same as: count = count * 3)
// Multiple operations
let value = 2;
value *= 2; // 4
value *= 2; // 8
value *= 2; // 16
console.log(value); // 16
// With decimals
let price = 10;
price *= 1.5;
console.log(price); // 15
// With expressions
let x = 5;
x *= (2 + 3); // x = x * (2 + 3) = x * 5
console.log(x); // 25Practical Examples
// Doubling every iteration
let bacteria = 1;
console.log(`Start: ${bacteria}`);
bacteria *= 2; // 2
console.log(`Hour 1: ${bacteria}`);
bacteria *= 2; // 4
console.log(`Hour 2: ${bacteria}`);
bacteria *= 2; // 8
console.log(`Hour 3: ${bacteria}`);
// Applying multiplier
let score = 100;
let multiplier = 2;
score *= multiplier;
console.log(`Score with multiplier: ${score}`); // 200
// Scaling dimensions
let width = 10;
let height = 20;
let scaleFactor = 1.5;
width *= scaleFactor; // 15
height *= scaleFactor; // 30
console.log(`New size: ${width}x${height}`); // New size: 15x30
// Compound interest simplified
let investment = 1000;
let rate = 1.05; // 5% growth
investment *= rate; // After year 1
investment *= rate; // After year 2
investment *= rate; // After year 3
console.log(`After 3 years: $${investment.toFixed(2)}`);
// After 3 years: $1157.63Division Assignment (/=)
Divides the left operand by the right operand and assigns the result to the left operand.
Syntax
x /= y
// Equivalent to: x = x / yExamples
// Basic usage
let total = 100;
total /= 4;
console.log(total); // 25 (same as: total = total / 4)
// Multiple operations
let value = 1000;
value /= 2; // 500
value /= 2; // 250
value /= 2; // 125
console.log(value); // 125
// With decimals
let distance = 100;
distance /= 2.5;
console.log(distance); // 40
// Division by zero (returns Infinity)
let x = 10;
x /= 0;
console.log(x); // InfinityPractical Examples
// Split bill equally
let billAmount = 120;
let people = 4;
billAmount /= people;
console.log(`Per person: $${billAmount}`); // Per person: $30
// Halving process
let resourcePool = 1024;
console.log(`Start: ${resourcePool}`);
resourcePool /= 2; // 512
console.log(`Level 1: ${resourcePool}`);
resourcePool /= 2; // 256
console.log(`Level 2: ${resourcePool}`);
resourcePool /= 2; // 128
console.log(`Level 3: ${resourcePool}`);
// Calculate average
let sum = 450;
let count = 5;
sum /= count;
console.log(`Average: ${sum}`); // Average: 90
// Depreciation
let assetValue = 10000;
let years = 5;
let annualDepreciation = assetValue / years;
assetValue -= annualDepreciation; // After year 1
console.log(`Value after 1 year: $${assetValue}`); // Value after 1 year: $8000Remainder Assignment (%=)
Divides the left operand by the right operand and assigns the remainder to the left operand.
Syntax
x %= y
// Equivalent to: x = x % yExamples
// Basic usage
let number = 17;
number %= 5;
console.log(number); // 2 (same as: number = number % 5)
// Multiple operations
let value = 100;
value %= 30; // 10 (100 % 30)
value %= 3; // 1 (10 % 3)
console.log(value); // 1
// With negative numbers
let x = -17;
x %= 5;
console.log(x); // -2 (sign follows dividend)Practical Examples
// Cycling through array indices
let colors = ["red", "green", "blue"];
let index = 0;
function nextColor() {
let color = colors[index];
index++;
index %= colors.length; // Wrap around to 0 when reaching array length
return color;
}
console.log(nextColor()); // "red"
console.log(nextColor()); // "green"
console.log(nextColor()); // "blue"
console.log(nextColor()); // "red" (wrapped around)
// Day of week cycling
let day = 0; // Sunday
for (let i = 0; i < 10; i++) {
console.log(`Day ${day}`);
day++;
day %= 7; // Keep between 0-6
}
// Distributing items evenly with remainder
let totalItems = 17;
let containers = 5;
let itemsPerContainer = Math.floor(totalItems / containers); // 3
totalItems %= containers; // 2 (leftover items)
console.log(`${itemsPerContainer} items per container, ${totalItems} leftover`);
// 3 items per container, 2 leftover
// Keep within range
let position = 0;
let gridSize = 10;
function moveRight(steps) {
position += steps;
position %= gridSize; // Wrap around grid
console.log(`Position: ${position}`);
}
moveRight(8); // Position: 8
moveRight(5); // Position: 3 (wrapped from 13)
moveRight(15); // Position: 8 (wrapped from 18)Exponentiation Assignment (**=)
Raises the left operand to the power of the right operand and assigns the result to the left operand.
Syntax
x **= y
// Equivalent to: x = x ** yNote: Introduced in ES2016 (ES7)
Examples
// Basic usage
let base = 2;
base **= 3;
console.log(base); // 8 (same as: base = base ** 3)
// Multiple operations
let value = 2;
value **= 2; // 4 (2²)
value **= 2; // 16 (4²)
value **= 2; // 256 (16²)
console.log(value); // 256
// With decimals
let x = 4;
x **= 0.5; // Square root
console.log(x); // 2
// With negative exponents
let y = 2;
y **= -1; // 1/2
console.log(y); // 0.5Practical Examples
// Exponential growth simulation
let population = 1000;
let growthRate = 1.05; // 5% growth
// After year 1
population **= 1;
population *= growthRate;
console.log(`Year 1: ${Math.round(population)}`); // 1050
// Squaring in iterations
let value = 2;
for (let i = 0; i < 4; i++) {
value **= 2;
console.log(`Iteration ${i + 1}: ${value}`);
}
// Iteration 1: 4
// Iteration 2: 16
// Iteration 3: 256
// Iteration 4: 65536
// Power accumulation
let energy = 2;
energy **= 3; // 8 (charged to level 1)
console.log(`Energy level 1: ${energy}`);
// Can't do energy **= 3 again on 8 as it would be too large
// Scientific calculation
let wavelength = 2;
wavelength **= -1; // Convert to frequency
console.log(`Frequency: ${wavelength}`); // 0.5Logical Assignment Operators (ES2021)
JavaScript ES2021 introduced three new logical assignment operators that combine logical operations with assignment.
Logical AND Assignment (&&=)
Assigns the right operand to the left operand only if the left operand is truthy.
Syntax
x &&= y
// Equivalent to: x = x && y
// Or more precisely: if (x) { x = y; }How It Works
// If x is truthy, assign y to x
// If x is falsy, keep x unchanged
let x = 10;
x &&= 20;
console.log(x); // 20 (x was truthy, so assigned 20)
let y = 0;
y &&= 20;
console.log(y); // 0 (y was falsy, so stayed 0)Examples
// Basic usage
let value = 5;
value &&= 10;
console.log(value); // 10 (5 is truthy, so assigned 10)
let emptyValue = 0;
emptyValue &&= 10;
console.log(emptyValue); // 0 (0 is falsy, kept as 0)
// With strings
let name = "John";
name &&= "Jane";
console.log(name); // "Jane" (non-empty string is truthy)
let emptyName = "";
emptyName &&= "Jane";
console.log(emptyName); // "" (empty string is falsy, stayed empty)
// With objects
let user = { name: "John" };
user &&= { name: "Jane", age: 30 };
console.log(user); // { name: "Jane", age: 30 }
let nullUser = null;
nullUser &&= { name: "Jane" };
console.log(nullUser); // null (null is falsy, stayed null)Practical Examples
// Update only if value exists
let config = {
theme: "dark",
fontSize: 14
};
config.theme &&= "light"; // Update theme if it exists
console.log(config.theme); // "light"
config.language &&= "en"; // Won't create new property
console.log(config.language); // undefined
// Conditional update
let userScore = 100;
let bonusEligible = true;
bonusEligible &&= (userScore * 1.1); // Apply bonus only if eligible
console.log(bonusEligible); // 110
// Update nested property safely
let settings = {
display: {
brightness: 50
}
};
settings.display &&= { ...settings.display, brightness: 80 };
console.log(settings.display.brightness); // 80
// Guard against falsy values
function processData(data) {
data &&= data.trim(); // Trim only if data is truthy
return data || "No data";
}
console.log(processData(" hello ")); // "hello"
console.log(processData("")); // "No data"
console.log(processData(null)); // "No data"Logical OR Assignment (||=)
Assigns the right operand to the left operand only if the left operand is falsy.
Syntax
x ||= y
// Equivalent to: x = x || y
// Or more precisely: if (!x) { x = y; }How It Works
// If x is falsy, assign y to x
// If x is truthy, keep x unchanged
let x = 0;
x ||= 20;
console.log(x); // 20 (x was falsy, so assigned 20)
let y = 10;
y ||= 20;
console.log(y); // 10 (y was truthy, so stayed 10)Examples
// Basic usage
let value = 0;
value ||= 10;
console.log(value); // 10 (0 is falsy, assigned 10)
let existingValue = 5;
existingValue ||= 10;
console.log(existingValue); // 5 (5 is truthy, kept 5)
// With strings
let name = "";
name ||= "Anonymous";
console.log(name); // "Anonymous" (empty string is falsy)
let existingName = "John";
existingName ||= "Anonymous";
console.log(existingName); // "John" (kept existing value)
// With null/undefined
let user = null;
user ||= { name: "Guest" };
console.log(user); // { name: "Guest" }
let definedUser = { name: "John" };
definedUser ||= { name: "Guest" };
console.log(definedUser); // { name: "John" }Practical Examples (Default Values)
// Setting default values
let username = "";
username ||= "Guest";
console.log(username); // "Guest"
// Configuration with defaults
let config = {
port: 0,
host: ""
};
config.port ||= 3000;
config.host ||= "localhost";
console.log(config); // { port: 3000, host: "localhost" }
// Function parameters default
function greet(name) {
name ||= "there";
console.log(`Hello, ${name}!`);
}
greet("John"); // "Hello, John!"
greet(""); // "Hello, there!"
greet(); // "Hello, there!"
// Loading state
let data = null;
function loadData() {
data ||= fetchFromAPI(); // Only fetch if data doesn't exist
return data;
}
// Form field defaults
let formData = {
email: "",
phone: "",
country: ""
};
formData.email ||= "example@email.com";
formData.country ||= "USA";
console.log(formData);
// { email: "example@email.com", phone: "", country: "USA" }
// Cache pattern
let cache = null;
function getExpensiveData() {
cache ||= computeExpensiveOperation();
return cache;
}⚠️ Be Careful with 0 and false
// ❌ Problem: 0 is falsy
let count = 0;
count ||= 10;
console.log(count); // 10 (but we wanted to keep 0!)
// ❌ Problem: false is falsy
let isActive = false;
isActive ||= true;
console.log(isActive); // true (but we wanted to keep false!)
// ✅ Solution: Use ?? if you want to preserve 0 and false
let count2 = 0;
count2 ??= 10;
console.log(count2); // 0 (preserved!)Nullish Coalescing Assignment (??=)
Assigns the right operand to the left operand only if the left operand is null or undefined.
Syntax
x ??= y
// Equivalent to: x = x ?? y
// Or more precisely: if (x === null || x === undefined) { x = y; }How It Works
// If x is null or undefined, assign y to x
// If x is any other value (including 0, false, ""), keep x unchanged
let x = null;
x ??= 20;
console.log(x); // 20 (null, so assigned 20)
let y = 0;
y ??= 20;
console.log(y); // 0 (0 is not null/undefined, so kept 0)Key Difference from ||=
// With ||= (checks for falsy)
let a = 0;
a ||= 10;
console.log(a); // 10 (0 is falsy)
let b = false;
b ||= true;
console.log(b); // true (false is falsy)
// With ??= (checks only for null/undefined)
let c = 0;
c ??= 10;
console.log(c); // 0 (0 is not null/undefined)
let d = false;
d ??= true;
console.log(d); // false (false is not null/undefined)Examples
// Basic usage
let value = null;
value ??= 10;
console.log(value); // 10 (null, assigned 10)
let definedValue = 5;
definedValue ??= 10;
console.log(definedValue); // 5 (not null/undefined, kept 5)
// With 0 (preserved!)
let count = 0;
count ??= 10;
console.log(count); // 0 (not null/undefined, kept 0)
// With false (preserved!)
let flag = false;
flag ??= true;
console.log(flag); // false (not null/undefined, kept false)
// With empty string (preserved!)
let text = "";
text ??= "default";
console.log(text); // "" (not null/undefined, kept empty string)
// With undefined
let x = undefined;
x ??= 20;
console.log(x); // 20 (undefined, assigned 20)Practical Examples
// Setting defaults for possibly null/undefined values
let userSettings = {
theme: null,
fontSize: undefined,
notifications: false,
volume: 0
};
userSettings.theme ??= "light";
userSettings.fontSize ??= 14;
userSettings.notifications ??= true; // Won't change (false is not null/undefined)
userSettings.volume ??= 50; // Won't change (0 is not null/undefined)
console.log(userSettings);
// {
// theme: "light",
// fontSize: 14,
// notifications: false, ✅ Preserved false
// volume: 0 ✅ Preserved 0
// }
// API response with optional fields
let apiResponse = {
data: null,
error: null,
status: 0
};
apiResponse.data ??= [];
apiResponse.error ??= "No error";
apiResponse.status ??= 200; // Won't change (0 is preserved)
console.log(apiResponse);
// { data: [], error: "No error", status: 0 }
// Function with optional parameter
function createUser(options) {
options ??= {}; // Default to empty object if null/undefined
options.role ??= "user";
options.active ??= true;
options.loginCount ??= 0;
return options;
}
console.log(createUser(null));
// { role: "user", active: true, loginCount: 0 }
console.log(createUser({ role: "admin", loginCount: 0 }));
// { role: "admin", active: true, loginCount: 0 }
// Lazy initialization
let expensiveResource = null;
function getResource() {
expensiveResource ??= initializeExpensiveResource();
return expensiveResource;
}
function initializeExpensiveResource() {
console.log("Initializing...");
return { data: "expensive data" };
}
getResource(); // Logs "Initializing..." and returns resource
getResource(); // Returns cached resource (doesn't initialize again)Comparison: ||= vs ??=
Understanding the difference is crucial for choosing the right operator.
Visual Comparison
// Test values
let testNull = null;
let testUndefined = undefined;
let testZero = 0;
let testFalse = false;
let testEmptyString = "";
let testValue = 5;
// Using ||= (assigns if falsy)
testNull ||= 10; // 10 (null is falsy)
testUndefined ||= 10; // 10 (undefined is falsy)
testZero ||= 10; // 10 (0 is falsy) ⚠️
testFalse ||= 10; // 10 (false is falsy) ⚠️
testEmptyString ||= 10; // 10 ("" is falsy) ⚠️
testValue ||= 10; // 5 (5 is truthy)
// Using ??= (assigns only if null/undefined)
testNull ??= 10; // 10 (null)
testUndefined ??= 10; // 10 (undefined)
testZero ??= 10; // 0 (preserved!) ✅
testFalse ??= 10; // false (preserved!) ✅
testEmptyString ??= 10; // "" (preserved!) ✅
testValue ??= 10; // 5 (not null/undefined)When to Use Each
Use ||= when:
- You want to replace ALL falsy values
- Empty strings, 0, false should be treated as "no value"
// Form validation - empty string should get default
let username = "";
username ||= "Anonymous"; // ✅ "Anonymous"Use ??= when:
- You only want to replace null/undefined
- 0, false, "" are valid values that should be preserved
// Settings where 0 and false are valid
let volume = 0;
volume ??= 50; // ✅ Keeps 0
let notifications = false;
notifications ??= true; // ✅ Keeps falseAssignment Operator Precedence
Assignment operators have low precedence and are right-associative.
Precedence Example
// Assignment has lower precedence than arithmetic
let x = 5 + 3; // First: 5 + 3 = 8, Then: x = 8
console.log(x); // 8
// Compound assignment also follows this
let y = 10;
y += 2 * 3; // First: 2 * 3 = 6, Then: y = y + 6 = 16
console.log(y); // 16Right-to-Left Associativity
// Multiple assignments are evaluated right to left
let a, b, c;
a = b = c = 5;
// Evaluation order:
// 1. c = 5 (c becomes 5, returns 5)
// 2. b = 5 (b becomes 5, returns 5)
// 3. a = 5 (a becomes 5, returns 5)
console.log(a, b, c); // 5 5 5
// Another example
let x, y;
x = (y = 10) + 5;
// 1. y = 10 (y becomes 10, returns 10)
// 2. 10 + 5 = 15
// 3. x = 15
console.log(x, y); // 15 10Common Patterns and Use Cases
Pattern 1: Accumulation
// Sum accumulation
let total = 0;
let items = [10, 20, 30, 40];
for (let item of items) {
total += item;
}
console.log(total); // 100
// String building
let html = "";
html += "<div>";
html += " <h1>Title</h1>";
html += " <p>Content</p>";
html += "</div>";Pattern 2: Counter Increment
// Click counter
let clickCount = 0;
function handleClick() {
clickCount += 1; // or clickCount++
updateDisplay();
}
// Score tracking
let score = 0;
function addPoints(points) {
score += points;
checkForLevelUp();
}Pattern 3: Reduction/Scaling
// Applying discount
let price = 100;
price *= 0.9; // 10% off
console.log(price); // 90
// Halving resources
let resources = 1000;
resources /= 2;
console.log(resources); // 500Pattern 4: Chained Updates
// Multiple operations
let value = 100;
value += 50; // 150
value *= 2; // 300
value -= 100; // 200
value /= 4; // 50
console.log(value); // 50Pattern 5: Default Values
// Using ||= for defaults
function processConfig(config) {
config ||= {};
config.timeout ||= 5000;
config.retries ||= 3;
config.debug ||= false;
return config;
}
// Using ??= for null/undefined only
function initializeSettings(settings) {
settings ??= {};
settings.volume ??= 50; // Won't override 0
settings.enabled ??= true; // Won't override false
return settings;
}Common Mistakes and Pitfalls
Mistake 1: Using = Instead of == or ===
// ❌ Wrong - assignment instead of comparison
let x = 10;
if (x = 5) { // Assigns 5 to x, always truthy
console.log("This always runs");
}
console.log(x); // 5 (x was changed!)
// ✅ Correct - comparison
let y = 10;
if (y === 5) {
console.log("This doesn't run");
}
console.log(y); // 10 (y unchanged)Mistake 2: Expecting Compound Assignment to Return Old Value
// Compound assignment returns NEW value, not old
let x = 10;
console.log(x += 5); // 15 (new value)
console.log(x); // 15
// If you need the old value, save it first
let y = 10;
let oldY = y;
y += 5;
console.log(`Old: ${oldY}, New: ${y}`); // Old: 10, New: 15Mistake 3: Using ||= with 0 or false
// ❌ Problem - 0 is falsy
let count = 0;
count ||= 10;
console.log(count); // 10 (but we wanted 0!)
// ✅ Solution - use ??=
let count2 = 0;
count2 ??= 10;
console.log(count2); // 0 (correct!)Mistake 4: Type Coercion Issues
// ❌ String concatenation instead of addition
let total = "10";
total += 5;
console.log(total); // "105" (string concatenation!)
// ✅ Convert to number first
let total2 = Number("10");
total2 += 5;
console.log(total2); // 15 (addition)Mistake 5: Forgetting Operator Precedence
// ❌ Unexpected result
let x = 5;
x += 2 * 3; // Might expect 21, but gets 11
console.log(x); // 11 (because 2 * 3 happens first)
// How it's evaluated:
// 1. 2 * 3 = 6
// 2. x = x + 6 = 5 + 6 = 11
// ✅ Use parentheses if you want different order
let y = 5;
y = (y + 2) * 3;
console.log(y); // 21Best Practices
1. Use Compound Assignments for Clarity
// ❌ Verbose
count = count + 1;
total = total + price;
score = score * multiplier;
// ✅ Concise
count += 1;
total += price;
score *= multiplier;2. Choose the Right Logical Assignment
// ❌ Wrong operator
let volume = 0;
volume ||= 50; // Changes 0 to 50 (might not be intended)
// ✅ Right operator
let volume2 = 0;
volume2 ??= 50; // Keeps 0 (only replaces null/undefined)3. Avoid Assignment in Conditions (Unless Intentional)
// ❌ Confusing
if (user = getUser()) { // Assignment!
console.log(user.name);
}
// ✅ Clear intent
user = getUser();
if (user) {
console.log(user.name);
}
// ✅ If intentional, add extra parentheses
if ((user = getUser())) { // Extra () shows it's intentional
console.log(user.name);
}4. Be Explicit with Type Conversions
// ❌ Relying on coercion
let total = "10";
total += 5; // "105"
// ✅ Explicit conversion
let total2 = Number("10");
total2 += 5; // 155. Use Parentheses for Complex Expressions
// ❌ Hard to read
x += y * z + a / b;
// ✅ Clearer with parentheses
x += (y * z) + (a / b);6. Don't Chain Too Many Operations
// ❌ Hard to debug
value += 10 * 2 - 5 / 2 + 3;
// ✅ Break into steps
let step1 = 10 * 2;
let step2 = 5 / 2;
value += step1 - step2 + 3;Practical Examples
Example 1: Shopping Cart
class ShoppingCart {
constructor() {
this.total = 0;
this.itemCount = 0;
}
addItem(price, quantity = 1) {
this.total += price * quantity;
this.itemCount += quantity;
}
removeItem(price, quantity = 1) {
this.total -= price * quantity;
this.itemCount -= quantity;
}
applyDiscount(percentage) {
this.total *= (1 - percentage / 100);
}
splitBill(people) {
return this.total / people;
}
}
let cart = new ShoppingCart();
cart.addItem(29.99, 2); // Add 2 items at $29.99
cart.addItem(15.50, 1); // Add 1 item at $15.50
cart.applyDiscount(10); // Apply 10% discount
console.log(`Total: $${cart.total.toFixed(2)}`); // Total: $67.93
console.log(`Per person: $${cart.splitBill(2).toFixed(2)}`); // Per person: $33.97Example 2: Game Score System
class GameScore {
constructor() {
this.score = 0;
this.multiplier = 1;
this.streak = 0;
}
addPoints(points) {
this.score += points * this.multiplier;
this.streak += 1;
// Increase multiplier every 5 streak
if (this.streak % 5 === 0) {
this.multiplier += 0.5;
}
}
loseLife() {
this.score -= 100;
this.multiplier = 1;
this.streak = 0;
}
getStatus() {
return {
score: Math.round(this.score),
multiplier: this.multiplier,
streak: this.streak
};
}
}
let game = new GameScore();
game.addPoints(10); // 10 points
game.addPoints(10); // 10 points
game.addPoints(10); // 10 points
game.addPoints(10); // 10 points
game.addPoints(10); // 10 points (streak = 5, multiplier increases)
game.addPoints(10); // 15 points (multiplier = 1.5)
console.log(game.getStatus());
// { score: 65, multiplier: 1.5, streak: 6 }Example 3: Configuration Manager
function createConfig(userConfig) {
let config = userConfig ?? {};
// Set defaults only if null/undefined
config.apiUrl ??= "https://api.example.com";
config.timeout ??= 5000;
config.retries ??= 3;
config.debug ??= false;
// These preserve 0 and false!
config.maxConnections ??= 10; // Won't override 0
config.cache ??= true; // Won't override false
return config;
}
console.log(createConfig(null));
// { apiUrl: "...", timeout: 5000, retries: 3, debug: false, ... }
console.log(createConfig({ timeout: 0, debug: false }));
// { apiUrl: "...", timeout: 0, retries: 3, debug: false, ... }Example 4: Text Builder
class TextBuilder {
constructor() {
this.text = "";
}
append(str) {
this.text += str;
return this; // For method chaining
}
appendLine(str) {
this.text += str + "\n";
return this;
}
repeat(times) {
let original = this.text;
for (let i = 1; i < times; i++) {
this.text += original;
}
return this;
}
clear() {
this.text = "";
return this;
}
toString() {
return this.text;
}
}
let builder = new TextBuilder();
builder
.appendLine("Hello")
.appendLine("World")
.append("!");
console.log(builder.toString());
// Hello
// World
// !Practice Exercises
Create a file called assignment-practice.js:
// Assignment Operators Practice
// Exercise 1: Bank Account
class BankAccount {
constructor(initialBalance) {
this.balance = initialBalance;
}
deposit(amount) {
// TODO: Add amount to balance using +=
}
withdraw(amount) {
// TODO: Subtract amount from balance using -=
// Check if sufficient funds first
}
addInterest(rate) {
// TODO: Add interest using *= (rate is percentage, like 5 for 5%)
}
getBalance() {
return this.balance;
}
}
// Test
let account = new BankAccount(1000);
account.deposit(500);
account.withdraw(200);
account.addInterest(5); // 5% interest
console.log(account.getBalance()); // Should be ~1365
// Exercise 2: Resource Manager
function manageResources() {
let wood = 100;
let stone = 50;
let gold = 0;
// TODO: Use compound assignments to:
// 1. Gather 50 more wood (+=)
// 2. Use 30 stone for building (-=)
// 3. Find gold mine that doubles current gold, then add 100 (*= and +=)
// 4. Split remaining stone among 2 storage units (/=)
return { wood, stone, gold };
}
console.log(manageResources());
// Should return: { wood: 150, stone: 10, gold: 100 }
// Exercise 3: Settings with Defaults
function initializeApp(userSettings) {
// TODO: Use ??= to set defaults only if null/undefined
// - theme: "light"
// - language: "en"
// - fontSize: 14
// - notifications: true
// - volume: 50
return userSettings;
}
// Test
console.log(initializeApp({ theme: "dark", volume: 0 }));
// Should preserve volume: 0 and add other defaults
// Exercise 4: Counter with Limits
class LimitedCounter {
constructor(max) {
this.count = 0;
this.max = max;
}
increment(amount = 1) {
// TODO: Add amount but don't exceed max
// Use += and Math.min()
}
decrement(amount = 1) {
// TODO: Subtract amount but don't go below 0
// Use -= and Math.max()
}
reset() {
// TODO: Reset to 0
}
getValue() {
return this.count;
}
}
// Test
let counter = new LimitedCounter(10);
counter.increment(5); // 5
counter.increment(8); // Should cap at 10
counter.decrement(3); // 7
console.log(counter.getValue()); // 7Summary
Congratulations! 🎉 You now have a comprehensive understanding of assignment operators in JavaScript.
Key Takeaways
✅ Simple Assignment (=)
- Assigns value to variable
- Returns the assigned value
- Right-to-left associative
✅ Compound Assignments:
+=Addition assignment-=Subtraction assignment*=Multiplication assignment/=Division assignment%=Remainder assignment**=Exponentiation assignment
✅ Logical Assignments (ES2021):
&&=Assign if truthy||=Assign if falsy (use for any falsy value)??=Assign if null/undefined (preserves 0, false, "")
✅ Key Differences:
||=replaces ALL falsy values??=replaces ONLY null/undefined- Choose based on whether 0, false, "" are valid values
✅ Best Practices:
- Use compound assignments for conciseness
- Choose
??=over||=when 0 and false are valid - Avoid assignment in conditions (unless intentional)
- Be explicit with type conversions
What's Next?
Excellent work! You now understand how to assign and update values efficiently.
In the next lesson, we'll explore Comparison Operators where you'll learn:
- Equality operators (
==,===,!=,!==) - Relational operators (
<,>,<=,>=) - When to use strict vs loose equality
- Common comparison pitfalls
- Best practices for comparisons