Skip to main content

JavaScript Type System

JavaScript Primitives and References

Written by Published

Primitives are copied by value and objects are copied by reference.

This single difference explains a whole category of confusing bugs.

It is why changing one variable can change another.

Example

Example

javascript

let a = 1;
let b = a;
b = 2;

console.log(a);

The output is 1: b got its own copy.

The Two Groups

Primitives: string, number, boolean, null, undefined, symbol, bigint.

Everything else is an object, including arrays and functions.

Assigning a primitive copies the value; assigning an object copies the reference.

Syntax

Syntax

javascript

let copy = original;       // primitive: a real copy
const copy2 = { ...obj };  // object: needs spreading

A plain assignment never copies an object.

Objects Are Shared

Both names point at the same object, so a change is visible through both.

Example

Example

javascript

const a = { count: 1 };
const b = a;

b.count = 2;

console.log(a.count);

The output is 2, which surprises people the first time.

Making a Real Copy

Spreading builds a new object with the same properties.

Example

Example

javascript

const a = { count: 1 };
const b = { ...a };

b.count = 2;

console.log(a.count + " and " + b.count);

The output is 1 and 2.

Arrays Behave the Same Way

An array is an object, so the same rule applies.

Example

Example

javascript

const a = [1, 2];
const b = a;
const c = [...a];

b.push(3);

console.log(a.length + " " + c.length);

The output is 3 2: b shared, c did not.

Passing to a Function

A function receives a copy of the reference, not a copy of the object.

So changing a property inside is visible outside.

Example

Example

javascript

function rename(user) {
  user.name = "Grace";
}

const person = { name: "Ada" };
rename(person);

console.log(person.name);

Assigning a whole new object inside would not be visible outside.

Comparison Follows the Same Rule

Two objects are equal only if they are the same object.

Example

Example

javascript

console.log(1 === 1);
console.log({ a: 1 } === { a: 1 });

const shared = { a: 1 };
console.log(shared === shared);

The output is true, false, true.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript Primitives and References</title>
</head>
<body>

  <h1>Primitives and References</h1>

  <p id="out"></p>

  <script>
    let numberA = 1;
    let numberB = numberA;
    numberB = 2;

    const objectA = { count: 1 };
    const objectB = objectA;
    objectB.count = 2;

    const objectC = { count: 1 };
    const objectD = { ...objectC };
    objectD.count = 2;

    document.getElementById("out").innerHTML =
      "Primitive original: " + numberA +
      "<br>Shared object original: " + objectA.count +
      "<br>Spread copy original: " + objectC.count;
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try a nested object:

Spread an object that contains another object and change the inner one.

Important Points

  • Primitives are copied by value.
  • Objects and arrays are copied by reference.
  • A plain assignment shares an object rather than copying it.
  • Spreading makes a real, but shallow, copy.
  • Objects are compared by identity, not contents.

Conclusion

This distinction is behind a large share of confusing JavaScript bugs.

Whenever a change appears in a place you did not expect, think about references.

Copying deliberately is the fix.