JavaScript Assignment

6 minute read

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 be 0, "", or false
  • ✅ 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 = inside if or while (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.

← Previous: JS Arithmetic Next: JS Strings →

Updated: