Objects in JavaScript are passed by reference, not by value

Sean Ottomanelli
6 min readMay 11, 2021

“Objects in JavaScript are passed by reference, not by value”. If you’ve ever taken a course on JavaScript you’ve probably heard some version of this phrase. It’s possible that upon hearing this sage wisdom you tattooed it onto the back of your hand or you wrote it onto a sticky note and crazy glued that sticky note right onto the center of your monitor. It’s more likely, however, that you wrote it in your notebook and then never thought about it again. I mean it doesn’t really matter. Right? …Wrong.

I recently finished my Flatiron School phase 1 paired project. It was a long and tedious week but my partner and I learned a lot and ultimately the project was a success. We did a lot of things right. We did a lot of things wrong though too. One of these missteps that cost us more grief than it probably should have was the oversight of the fact that objects in JavaScript are passed by reference, not by value.

Our app is simple. It’s called Burger Builder. After a user logs in they are presented with the option to build a burger or view burgers that other users have built. If the user decides to build a burger a swatch of buttons appears.

Each button sends a burger ingredient to the ingredient pile in the center of the screen. One by one the ingredients pile up in an overlapping fashion ultimately forming a burger.

burger being built

If the user decides they want to remove an ingredient they previously added to the burger they can click on an ingredient to remove it from the stack.

The way my partner and I initially tackled this feature was as follows:

When a user clicks on an ingredient button a few things happen.

  1. An ingredient counter increases by 1.
  2. The ingredient object embedded in the ingredient button event listener is passed to a “displayBurgerArray”. Said object is given a new ID based on the ingredient’s name and the counter’s value. The counter never repeats thus ensuring a unique ID.
  3. The image URL contained in each of the objects in the displayBurgerArray is rendered and the ingredient pile, or “burger”, takes shape.

When a user clicks on an ingredient in the ingredients pile an event listener is triggered which invokes a function that finds the ingredient in the displayBurgerArray with the same ID as the one that was clicked and deletes that ingredient from the displayBurgerArray. The visual pile renders the change, and the ingredient is no more.

The method described above is logical. It works… or does it?

After implementing this code my partner and I tested our app by building a big juicy double cheeseburger. All of the ingredients stacked as they should. We console logged the ingredient objects as we stacked them. The first ingredient, a bottom bun, had an ID of “bottomBun1”. The second ingredient, a beef patty, had an ID of “beefPatty2”. As we added more ingredients the trend continued: “cheddarSlice3”, “beefPatty4”, cheddarSlice5, “ketchup6”, and so on and so forth. Everything seemed to be working in that respect. As for the delete functionality, upon clicking on the ketchup the ketchup ingredient object was removed from the displayBurgerArray and subsequently from the pile. Same with the bottom bun. For the beef patties however, by clicking on one of the patties in the double cheeseburger stack all two of the beef patties were deleted. What gives? Is it a problem with the delete ingredient callback function.

As it turns out the delete-ingredient callback function was doing it’s job perfectly. It was finding and deleting the ingredient object in the displayBurgerArray with the ID equal to the ingredient that was clicked in the pile. The actual problem, as we found by inspecting our displayBurgerArray, was that all of the beef patties had the same ID. We worked so hard to give them unique ID’s. Did our trusty counter fail us? How was this possible?

The answer is “Objects in JavaScript are passed by reference, not by value”. Remember when I said this?: “The ingredient object embedded in the ingredient button event listener is passed to a “displayBurgerArray”. Said object is given a new ID based on the ingredient’s name and the counter’s value, thus ensuring a unique ID.” When my partner and I passed the ingredient object to the displayBurgerArray we did so without making a new copy of the object in memory. For this reason we were passing a reference to the same beef patty object every time we clicked the beef patty ingredient button. When we thought we were giving a unique ID to the second beef patty in the displayBurgerArray we were actually assigning a new ID to the beef patty object that the second beef patty object was referencing, which was also the same beef patty object that the first beef patty was referencing therefor effectively giving both the first and second beef patties the same ID. Thats a long beefy sentence. The whole thing is a little tough to swallow but -puns aside- that’s what was actually happening. Follow along to see this phenomenon in action.

Let’s make a variable called originalBeefPatty and assign it to a beef patty object:

Now let’s make a different variable, beefPatty1 and set it equal to original beef patty. While we’re at it, let’s give that new object variable an ID of “beefPatty1”.

Now lets compare originalBeefPatty and BeefPatty1:

They’re the same. This is because when I set beefPatty1 equal to originalBeefPatty, I was passing a reference from originalBeefPatty to beefPatty1, and not the information contained within the object. Any change(s) I make to one of the variables actually changes the referenced object and since the other variable references that same object the change(s) can also be observed on the other object.

At the end of the day, like many of the problems we encountered during project week this one was fairly simple to solve after we were able to fully wrap our heads around what had gone wrong. In this case the solution to our problem was using the spread operator to create a copy of each ingredient object before appending them to the displayBurgerArray.

By doing this, we are divorcing the ingredient from the original reference in memory, creating a sort of pressure gap between the original object and our new one so that when a new ID is given to the new object it is truly unique:

By adding in the spread operator to create the new object the IDs remain unique and the delete function worked as planned.

Objects in JavaScript are passed by reference, not by value. It’s easy to forget or overlook this detail but it’s actually an important detail of the JavaScript language.

--

--