Assignment Operators
Assignment is how a variable gets a value. The plain = is the workhorse, but JavaScript has a family of compound operators that combine assignment with another operation — +=, ||=, ??= and so on — plus destructuring assignment, which can pull values out of objects and arrays in a single statement.
Plain assignment
let total = 0;
total = 100; // re-assignment
const user = { name: "Ada" };
user.name = "Lin"; // assigning to a property (allowed even though user is const)
const arr = [1, 2, 3];
arr[0] = 99; // assigning to an indexThe left-hand side of = must be a target — a variable, a property, an array index, or a destructuring pattern. The right-hand side is any expression.
Compound assignment
Every arithmetic and bitwise operator has a compound form that reads "do the operation and store the result".
let n = 10; n += 5; // n = n + 5 → 15 n -= 3; // n = n - 3 → 12 n *= 2; // n = n * 2 → 24 n /= 4; // n = n / 4 → 6 n %= 4; // n = n % 4 → 2 n **= 3; // n = n ** 3 → 8 let s = "foo"; s += "bar"; // s = s + "bar" → "foobar" // Bitwise variants exist too let b = 0b1010; b &= 0b1100; // 0b1000 b |= 0b0011; // 0b1011 b ^= 0b1010; // 0b0001 b <<= 2; // 0b0100 b >>= 1; // 0b0010 b >>>= 0; // unsigned right shift
Logical assignment
Added in ES2021, these combine short-circuiting with assignment. They only assign when the variable's current value clears a particular check.
// ||= — assign if the current value is FALSY let a = ""; a ||= "default"; // a is now "default" // &&= — assign if the current value is TRUTHY let b = "ready"; b &&= b.toUpperCase(); // b is now "READY" // ??= — assign if the current value is null or undefined let c = 0; c ??= 100; // c is still 0 (0 is not nullish) let d = null; d ??= 100; // d is now 100
??= is the safest of the three for "set a default unless something was explicitly assigned" — it doesn't fire on 0, "" or false.
Lazy initialisation pattern
function getCache() {
cache ??= new Map(); // create on first call only
return cache;
}
let cache;Chained assignment
Because = returns the assigned value, you can write a = b = c = 0 to set them all to zero.
let a, b, c; a = b = c = 0; console.log(a, b, c);
0 0 0
Destructuring assignment
A pattern on the left of = can pull values out of arrays and objects in one shot. It is one of the most beloved features of modern JavaScript.
Array destructuring
const [first, second, third] = [10, 20, 30]; console.log(first, second, third); // 10 20 30 // Skip elements with commas const [, , c] = [1, 2, 3]; console.log(c); // 3 // Rest to collect the tail const [head, ...rest] = [1, 2, 3, 4]; console.log(head, rest); // 1 [2, 3, 4] // Defaults if the value is undefined const [a = 1, b = 2] = [10]; console.log(a, b); // 10 2 // Swap two variables — no temp needed let x = 1, y = 2; [x, y] = [y, x]; console.log(x, y); // 2 1
Object destructuring
const user = { name: "Ada", role: "admin", age: 36 };
// Pull out properties
const { name, role } = user;
console.log(name, role); // Ada admin
// Rename
const { name: userName } = user;
console.log(userName); // Ada
// Defaults
const { country = "UK" } = user;
console.log(country); // UK
// Rest
const { age, ...rest } = user;
console.log(age, rest); // 36 { name: "Ada", role: "admin" }Destructuring in function parameters
Where destructuring really pays off: cleanly accepting an "options" object.
function createUser({ name, role = "user", active = true } = {}) {
return { name, role, active };
}
createUser({ name: "Ada" });
// { name: "Ada", role: "user", active: true }
createUser({ name: "Lin", role: "admin" });
// { name: "Lin", role: "admin", active: true }The = {} at the end of the parameter list lets you call createUser() with no argument at all — the function still finds an empty object to destructure.
Re-assigning to const targets
const prevents re-binding; it doesn't prevent mutation or property assignment.
const user = { name: "Ada" };
user.name = "Lin"; // ok — mutating the object
user.role = "admin"; // ok — adding a property
// user = { name: "Lin" }; // TypeError — re-binding
const arr = [1, 2, 3];
arr.push(4); // ok — mutation
arr[0] = 99; // ok
// arr = []; // TypeErrorOperator chaining gotcha
// Pitfall: easy to write = instead of ==
if (user.role = "admin") { // ASSIGNS "admin" to user.role, then evaluates "admin" (truthy)
// always runs!
}
// Correct:
if (user.role === "admin") {
// ...
}