cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Objects & references

Learn why two variables can point to the same object, how object identity affects functions and comparisons, and when shallow or deep copies are the safer choice.

By the end, you can
  • 01
    Trace shared objectsExplain why changing one variable’s object can appear through another variable.
  • 02
    Predict calls and comparisonsTell when a function mutation escapes and when === checks identity.
  • 03
    Choose the right copyUse spread, Object.assign, or structuredClone with the right expectations.

One object can have many names

In the Data types lesson you met the big split: primitives copy the value, while objects copy a reference. This lesson slows that sentence down until you can predict it in real programs. If two variables point at the same object, changing the object through one variable is visible through the other variable too.

A reference is the value JavaScript uses to reach an object. You do not see the reference directly; you see the object it leads to. For this lesson, imagine the reference as an address written on an envelope.

The short version

Object variables do not contain the whole object. They contain a way to find it. Copying the variable copies that way to find it, not a brand-new object.

Real-life analogyTwo envelopes, one house

If two people hold envelopes with the same home address, both visit the same house. Copying the address did not build another house. If one person repaints the door, the other person sees the new color because there is still only one house.

In real life: A house
In JavaScript: The object
In real life: An address on an envelope
In JavaScript: A reference in a variable
In real life: Copying the address
In JavaScript: const b = a;
In real life: Repainting the house
In JavaScript: Changing a property like b.score = 2

Where the analogy stops: JavaScript references are not postal addresses and you cannot inspect or do math with them. The analogy only explains why two names can lead to one object.

This matters in arrays, settings objects, function parameters, state updates, and any code that tries to avoid accidental mutation. Later lessons named Memory: primitives vs objects, Freezing, sealing & immutability, Immutability, and Messaging & structured cloning go deeper. Today we build the everyday mental model.

Values vs references

INTERACTIVE

Primitives such as numbers, strings, booleans, null, and undefined behave like self-contained values. If you copy a number, changing one variable later does not change the other. Objects are different: the copied value is a reference to the same object.

Primitive copy vs object referencePop out in the code editor (opens in a new tab)JavaScript
let x = 1;
let y = x;
y = 2;
console.log(x); // 1

const a = { score: 1 };
const b = a;
b.score = 2;
console.log(a.score); // 2

The diagram below uses real objects and real property values, then draws a conceptual picture: variable names on the left, object cards on the right. It is not engine memory inspection; it is a teaching picture of the references your code created.

Draw the references
Reference stepsPop out in the code editor (opens in a new tab)JavaScript
const a = { score: 1 };const b = a;b.score = 2;const c = { ...a };c.score = 3;const d = { ...a, stats: { ...a.stats } };
Conceptual pictureAlias
Variables
a→ #1
b→ #1
Objects
#1{ score: 1 }
Step 1 of 5Alias

b receives the same reference as a.

A conceptual diagram built from real objects in this component. It shows references; it is not a memory inspector.

Notice the two separate questions. Are two variables pointing at the same object? And if there is a copy, are any nested objects still shared? We will return to the nested case in the shallow-copy section.

Call by sharing

STEP THROUGH

Function parameters follow the same rule. When you pass an object to a function, the parameter receives a copy of the reference. That means the function can mutate the shared object. But if the function reassigns the parameter, only that local parameter points somewhere new.

This behavior is often called call by sharing. It is not pass-by-reference in the sense that the function can replace the caller’s variable. It shares the object, not the caller’s binding.

Mutate a property or reassign the parameter?
Step 0 of 4Ready
Your turn: follow the blue line

Switch the function body. A property write escapes; a parameter reassignment does not.

Running in
  1. script
Next: line 5
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
function addBadge(user) {  user.badge = "mentor";} addBadge(ada);console.log(ada.badge);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Switch the function body

Changing the body starts a fresh replay with real values.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Real-life analogyA borrowed key vs a new keyring

A friend with your key can enter the same house and move a chair. You will see that change later. But if your friend replaces the key on their own keyring, your keyring does not change.

In real life: Handing a friend your house key
In JavaScript: Passing an object reference to a parameter
In real life: They rearrange the furniture
In JavaScript: The function mutates a property
In real life: They put a different key on their own keyring
In JavaScript: The function reassigns its parameter

Where the analogy stops: The friend analogy has people and intent. JavaScript just copies a value into a parameter and follows assignments exactly.

Comparing objects

STEP THROUGH

The Comparisons lesson taught that === means strict equality. With objects, strict equality checks identity: are these two references pointing at the exact same object? It does not compare keys and values.

Compare identities, not contents
Step 0 of 6Ready
Your turn: follow the blue line

Predict each comparison. Remember: for objects, === asks whether both sides are the same object.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const b = a;const c = { score: 1 }; console.log(a === b);console.log(a === c);console.log({ score: 1 } === { score: 1 });
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Ways people compare objects
GoalExampleImportant warning
Same object identitya === bTrue only when both sides point at the same object.
Flat contentsCompare keys, then values with Object.isWorks only for the level you check; nested objects need their own rules.
Quick JSON stringJSON.stringify(a) === JSON.stringify(b)Key order can change the string, and JSON loses values like undefined and functions.

For simple flat objects, a content comparison can be written by checking that both objects have the same keys and each key has the same value. That is a choice your code makes; it is not what === does automatically.

Shallow copies with spread and Object.assign

INTERACTIVE

A shallow copy creates a new top-level object and copies the top-level properties into it. The common forms are { ...obj } and Object.assign(, obj). Arrays have the same idea with [...array].

Shallow copy: new shell, shared nested objectPop out in the code editor (opens in a new tab)JavaScript
const user = {  name: "Ada",  address: { city: "Pune" },}; const shallow = { ...user };shallow.address.city = "Kochi"; const deep = structuredClone(user);deep.address.city = "Jaipur"; console.log(user.address.city);console.log(deep.address.city);

In that code, shallow is a different top-level object, but shallow.address and user.address are the same nested object. Changing shallow.address.city changes that shared nested object, so the original user appears to change too.

Shared or independent?
  • const b = a; after a is an object
  • const b = { score: a.score };
  • const b = { ...a };
  • const b = Object.assign({}, a);
  • const queue2 = queue1; when queue1 is an array
  • A function parameter receiving an object argument
Try it yourself
0 of 6 correct

Decide whether each line leaves two names sharing one object, or creates an independent top-level object.

Choose a category for every card. You can change an answer at any time; Reset clears them all.
New house, same furniture boxes

A shallow copy is like building a new house, then moving in boxes that still contain the same shared furniture. Changing the paint on the new house is independent. Changing the shared sofa is visible in both places.

Deep copies with structuredClone

A deep copy also copies nested data. Modern browsers and recent Node versions provide structuredClone(value), the same family of cloning rules used by web messaging APIs. It handles plain objects, arrays, Dates, Maps, Sets, and many other data values. It does not clone functions or DOM nodes; trying to clone a function throws a DataCloneError.

Copy methods at a glance
MethodWhat it copiesWatch out
Assignment: const b = aOnly the referenceBoth names reach the same object.
Spread: { ...a }Top-level own propertiesNested objects stay shared.
Object.assign({}, a)Top-level own propertiesSame shallow behavior as spread for this use.
structuredClone(a)Nested cloneable dataFunctions and DOM nodes are not cloneable.
JSON.parse(JSON.stringify(a))JSON-safe data onlyDates become strings; undefined and functions disappear.

Use structuredClone when you truly need independent nested data. Do not use it as a reflex. Deep copies can be more expensive, and some objects represent things that should not be copied. If you need to update only one branch, copying only the changed path is often clearer.

const doesn’t freeze

The Variables lesson introduced const: it means the variable binding cannot be reassigned. It does not make the object immutable. You can still change properties on a const object, because the variable still points at the same object.

The binding is constant; the object is notPop out in the code editor (opens in a new tab)JavaScript
const user = { name: "Ada" };user.name = "Grace";     // allowed// user = { name: "Lin" }; // TypeError if you run itconsole.log(user.name);   // "Grace"

Object.freeze(user) is a separate tool, and it is shallow: it freezes the object itself, not every nested object inside it. The Freezing, sealing & immutability lesson goes into that topic later.

Where you’ll use this

References show up whenever code shares data. A few everyday examples:

  • A function receives a settings object. If it changes settings.theme, the caller’s object changes too.
  • UI state often needs a new object so change detection can see that something changed. A shallow copy is common for top-level updates.
  • Tests often compare object contents, not object identity, because two correct functions can return equal-looking but different objects.
  • Messages between browser contexts use structured cloning rules, which is why Messaging & structured cloning later deserves its own lesson.

Common misconceptions

“Objects are copied when assigned.”

The reference is copied. The object is not copied unless you explicitly create another object.

“JavaScript passes objects by reference.”

Property mutations are shared, but parameter reassignments are local. “Call by sharing” is the more precise beginner-friendly phrase.

“Two objects with the same properties are equal.”

=== compares identity for objects. If you want a content comparison, write or use a content comparison.

“Spread is a deep copy.”

Spread and Object.assign are shallow. Nested objects remain shared unless you copy them too.

“const makes an object safe from changes.”

const protects the binding, not the object. It stops user = ..., not user.name = ....

Practice: objects and references

5 EXERCISES
Exercise 1 · Warm-upPredict the shared change

Trace the aliases and predict the console output.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const a = { score: 1 };
const b = a;
b.score = 5;
console.log(a.score);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeFix a mutating function

    The function renames a user by mutating its input. Rewrite it so the original object is not changed.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    function renameUser(user, name) {
      user.name = name;
      return user;
    }

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeMake nested settings independent

      Given a nested settings object, make a copy before changing a nested color.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const copy = structuredClone(settings);
      copy.theme.color = "blue";

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengeCompare two flat objects

        Write or study a function that returns true for flat objects with the same keys and values.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function sameFlatObject(left, right) {
          const leftKeys = Object.keys(left);
          const rightKeys = Object.keys(right);
          return leftKeys.length === rightKeys.length &&
            leftKeys.every((key) => Object.hasOwn(right, key) && Object.is(left[key], right[key]));
        }

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · PracticeExplain the const surprise

          Run the snippet and explain why the property change is allowed.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const pet = { name: "Momo" };
          pet.name = "Pip";
          console.log(pet.name);

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            8 QUESTIONS

            Choose once, then read every explanation. Wrong answers teach the edge cases.

            Lesson quiz · 8 questionsScore: first tries count
            1. Question 1 of 8What does this aliasing code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const a = { score: 1 };
              const b = a;
              b.score = 2;
              console.log(a.score);

              Choose an answer to see the explanation.

            2. Question 2 of 8Which sentence best describes call by sharing?

              Choose an answer to see the explanation.

            3. Question 3 of 8What does strict equality check for objects?

              Choose an answer to see the explanation.

            4. Question 4 of 8What does this identity check print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const a = { city: "Oslo" };
              const b = { city: "Oslo" };
              console.log(a === b);

              Choose an answer to see the explanation.

            5. Question 5 of 8What does a shallow copy with spread copy?

              Choose an answer to see the explanation.

            6. Question 6 of 8What does this shallow copy print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const user = { address: { city: "Rome" } };
              const copy = { ...user };
              copy.address.city = "Milan";
              console.log(user.address.city);

              Choose an answer to see the explanation.

            7. Question 7 of 8Which value can structuredClone copy correctly?

              Choose an answer to see the explanation.

            8. Question 8 of 8What does const freeze in const user = { name: "Ada" }?

              Choose an answer to see the explanation.

            Key takeaways

            • Variables that hold objects hold references to objects.
            • Copying an object variable copies the reference, not the object.
            • Function parameters share object references, but reassigning the parameter is local.
            • === compares object identity, not matching contents.
            • Spread and Object.assign are shallow; structuredClone copies cloneable nested data.
            • const prevents reassignment of the binding, not mutation of the object.

            Remember the one-liner.
            An object variable is a way to reach an object; two variables can reach the same one.

            Up next: Methods & this.

            CompleteFrontend Clear concepts. Working examples.