Why do JavaScript objects sometimes behave unexpectedly?
Let’s say we are making objects for different kinds of pizzas. We define a pizza object, like so:
const pizzaMargherita = { name: "Margherita", mainIngredient: "Mozzarella" };
We need to make another pizza with the same mainIngredient
. So we copy the first object:
const pizzaMargherita = { name: "Margherita", mainIngredient: "Mozzarella" }; const pizzaRomana = pizzaMargherita; console.log("Pizza Margherita: ", pizzaMargherita); console.log("Pizza Romana: ", pizzaRomana);
We get the following output:
Pizza Margherita: { name: "Margherita", mainIngredient: "Mozzarella" } Pizza Romana: { name: "Margherita", mainIngredient: "Mozzarella" }
Next, we change the name of the pizzaRomana
to "Romana"
:
pizzaRomana.name = "Romana";
And we get the following output:
Pizza Margherita: { name: "Romana", mainIngredient: "Mozzarella" } Pizza Romana: { name: "Romana", mainIngredient: "Mozzarella" }
The name for pizzaRomana
changes, but so does the name of pizzaMargherita
. Why is the name changed for pizzaMargherita
even though we are not making any changes to it?
To understand the unexpected behavior of JavaScript objects, we first need to understand the difference between the primitive data types and reference type data types.
Primitive data types are basic data types that are always saved and accessed by their value in the memory. Primitive data types include string
, number
, bigint
, boolean
, undefined
, symbol
, and null
.
When we assign a primitive data type to a variable, the actual value is stored in memory.
Let’s take a look at the following example:
const r = "Romana"; let n = r; n = "New Romana"; console.log(r); console.log(n);
We get the following output:
Romana New Romana
We created a new variable of type string
, which is a primitive type data.
When we copy r
to n
, we are actually creating a new piece of data with the value Romana
. That is why when we change the value of n
to New Romana
, the value of r
remains unchanged.
Reference type data types on the other hand are pieces of data with a collection of properties. JavaScript objects, arrays, and functions are reference type data types.
When we assign reference type data to a variable, an object is created in the memory and its reference, or address, is stored as the value of the variable, rather than the actual object itself.
If we create a copy of this variable, JavaScript doesn’t create a new object, like it does with primitive data types. It just stores the reference to the same object as a value for the new variable.
When we created the object pizzaMargherita
above, an object was created and its address in the memory was stored as a value for pizzaMargherita
.
When we made a copy of this object, pizzaRomana
, the same address was stored as the value for pizzaRomana
.
When we make changes to the name
property of pizzaRomana
, we are making changes to the same object that was created using the variable pizzaMargherita
.
If we want to make two unique objects in the memory that are independent of each other we should use the spread operator to copy the object.
Get actionable, code-level insights to resolve JavaScript performance bottlenecks and errors.
Create a free Sentry account
Create a JavaScript project and note your DSN
Grab the Sentry JavaScript SDK
<script src="https://browser.sentry-cdn.com/7.112.2/bundle.min.js"></script>
Sentry.init({ dsn: 'https://<key>@sentry.io/<project>' });
Loved by over 4 million developers and more than 90,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.