JavaScript Assignment
The = operator puts a value into a variable. Around that one operator sits a family of compound assignments (+=, *=, ??=, …) that update a variable based on its current value. Modern JavaScript also lets you destructure assignments — pulling multiple values out of arrays and objects in one line.
The Basic Assignment Operator
let x = 5; // declare and assign
x = 10; // reassign
const PI = 3.14; // declare-and-assign (const can't be reassigned)
= is right-to-left associative — the right-hand side is evaluated first, then stored.
let a, b, c;
a = b = c = 5; // parses as a = (b = (c = 5))
console.log(a, b, c); // 5 5 5
Assignment is also an expression — it returns the assigned value, which is what makes chaining work.
Compound Assignment Operators
Each combines an operator with =, modifying the variable in place.
let x = 10;
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
| Op | Equivalent | Notes |
|---|---|---|
= |
— | Basic assignment |
+= |
x = x + y |
Also concatenates strings |
-= |
x = x - y |
|
*= |
x = x * y |
|
/= |
x = x / y |
|
%= |
x = x % y |
|
**= |
x = x ** y |
|
<<= |
x = x << y |
Bitwise shift |
>>= |
x = x >> y |
|
>>>= |
x = x >>> y |
Zero-fill shift |
&= |
x = x & y |
Bitwise AND |
\|= |
x = x \| y |
Bitwise OR |
^= |
x = x ^ y |
Bitwise XOR |
&&= |
x && (x = y) |
Logical AND assign |
\|\|= |
x \|\| (x = y) |
Logical OR assign |
??= |
x ?? (x = y) |
Nullish assign |
String Concatenation with +=
let greeting = "Hello";
greeting += ", world"; // "Hello, world"
greeting += "!"; // "Hello, world!"
For building large strings, prefer an array and join() (faster for many concatenations):
const parts = [];
for (let i = 0; i < 1000; i++) parts.push(`item ${i}`);
const result = parts.join("\n");
Logical Assignment (ES2021)
The three newest assignment operators — &&=, ||=, ??= — combine a logical test with assignment. They’re concise replacements for common patterns.
||= — Assign if Falsy
let name = "";
name ||= "anonymous"; // assigns if name is falsy
console.log(name); // "anonymous"
// Equivalent to:
name = name || "anonymous";
// Or the long form:
if (!name) name = "anonymous";
??= — Assign if Null/Undefined
let count; // undefined
count ??= 10; // assigns 10
console.log(count); // 10
let zero = 0;
zero ??= 10; // does NOT assign — 0 is not nullish
console.log(zero); // 0
// Compare with ||=:
let zero2 = 0;
zero2 ||= 10; // ❌ overwrites — 0 is falsy
console.log(zero2); // 10
&&= — Assign if Truthy
The lesser-used cousin. Only assigns when the current value is truthy.
let user = { name: "Ada" };
user.name &&= user.name.trim(); // trim only if truthy
let nope = null;
nope &&= "won't run"; // null stays null
| Operator | Assigns When | Common Use |
|---|---|---|
\|\|= |
left is falsy | Default values (legacy) |
??= |
left is null or undefined |
Default values (modern) |
&&= |
left is truthy | Conditional update / sanitise |
Tip: ??= is the right choice for “set a default if missing” — 0, "", and false are real values that you don’t want to overwrite.
Side-by-Side
let a = 0, b = 0, c = 0;
a ||= 10; // 10 — falsy gets replaced
b ??= 10; // 0 — 0 isn't nullish
c &&= 10; // 0 — 0 isn't truthy
let x = null, y = null, z = null;
x ||= 10; // 10
y ??= 10; // 10
z &&= 10; // null
Destructuring Assignment — A Quick Look
ES6 lets you pull values out of arrays and objects in one assignment. Full chapter is 33; here’s the taste:
Array destructuring
const [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
// Skip elements with commas
const [, second] = [1, 2, 3];
console.log(second); // 2
// Rest pattern
const [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
Object destructuring
const user = { name: "Ada", age: 36 };
const { name, age } = user;
console.log(name, age); // "Ada" 36
// Rename and default
const { name: who, role = "guest" } = user;
console.log(who, role); // "Ada" "guest"
Swap variables
A classic one-liner:
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
Without destructuring you’d need a temp variable. With destructuring it’s a single line.
Assignment as an Expression
Because = returns a value, you can use it inside other expressions — but just because you can, doesn’t mean you should.
// Sometimes useful — assign inside a condition
let line;
while ((line = readLine()) !== null) {
console.log(line);
}
// Almost always confusing
if (x = 5) { /* always true, and silently reassigns x! */ }
Warning: Beware accidental assignment in conditionals. if (x = 5) is valid JavaScript but probably a typo for if (x === 5). ESLint’s no-cond-assign rule will catch these.
Reference vs Value Assignment
For primitives, assignment copies the value. For objects, it copies the reference (the pointer).
// Primitive — independent copies
let a = 5;
let b = a;
b = 99;
console.log(a, b); // 5 99
// Object — both names point at the same object
let x = { v: 5 };
let y = x;
y.v = 99;
console.log(x.v); // 99 ← same object!
To copy an object’s properties (shallow), use spread:
const original = { a: 1, b: 2 };
const copy = { ...original };
copy.a = 99;
console.log(original.a); // 1 — unaffected
A Realistic Example
function applyDefaults(config) {
// Modern destructuring + defaults
const {
apiBase = "https://api.example.com",
timeout = 5000,
retries = 3,
headers = {},
} = config ?? {};
// Mutate result conditionally
const result = { apiBase, timeout, retries, headers };
result.headers["X-Client"] ??= "web"; // set only if missing
result.headers["Accept"] ??= "application/json";
return result;
}
applyDefaults({ apiBase: "https://test.io" });
// {
// apiBase: "https://test.io",
// timeout: 5000,
// retries: 3,
// headers: { "X-Client": "web", "Accept": "application/json" }
// }
Destructuring with defaults at the top, ??= to set missing fields without overwriting — clean and intentional.
Best Practices Checklist
- ✅ Prefer
??=over||=when defaulting values that might legitimately be0,"", orfalse - ✅ Use destructuring to unpack values you’ll use individually
- ✅ Use the spread operator (
{...obj},[...arr]) to copy before mutating - ✅ Keep one assignment per line for readability
- ❌ Don’t chain assignments (
a = b = c = 5) — it hides intent and can leak globals in non-strict mode - ❌ Don’t use
=insideiforwhile(use===or wrap in((…))if intentional) - ❌ Don’t assume assigning an object makes a copy — it doesn’t
What’s Next?
Numbers handled, assignment mastered — now we turn to the other workhorse data type: strings. We’ll cover quoting styles, template literals, escape sequences, and immutability.