JS Objects - Silent Mutation Broke User Sessions
Object mutation from reference copy in JavaScript corrupted user sessions: changing one user's email altered others.
- JavaScript objects store key-value pairs, bundling related data into one unit
- Two access methods: dot notation (static keys) and bracket notation (dynamic keys)
- Objects are reference types: assignment copies the reference, not the value
- Accessing a missing property returns undefined silently — no error thrown
- Performance tip: object property lookup is O(1) on average, but deleting properties can deoptimize hidden classes
- Production insight: a typo in property name causes undefined and silent failures; use optional chaining or strict checks to catch early
Think of a JavaScript object like a contact card in your phone. That card has a name, a phone number, an email, and maybe a photo — all bundled together under one person. In JavaScript, an object lets you group related pieces of information about one 'thing' into a single place, instead of scattering them across a dozen separate variables. Just like you'd look up someone by their name to find their number, you look up a property by its key to find its value.
Every real-world app you use — Instagram, Spotify, your bank's website — is built on data. A song has a title, an artist, a duration, and a genre. A user has a name, an email, and an age. If you tried to store all of that in separate, disconnected variables, your code would become impossible to manage before you even got started. JavaScript objects are the solution to this exact problem, and they're at the heart of almost everything you'll ever build on the web.
Before objects, imagine needing to track five pieces of information about 100 users. That's 500 variables. And when you pass data to a function, you'd need to pass all five separately every single time. Objects let you wrap all related data into one tidy package and hand it around your code as a single unit. They reflect how we naturally think about things in the real world — as entities with multiple characteristics.
By the end of this article you'll know how to create objects from scratch, read and update their properties using both dot notation and bracket notation, add and delete properties on the fly, loop over an object's contents, and understand the difference between primitive values and objects (a concept that trips up almost every beginner). You'll be ready to use objects confidently in real projects.
What Is a JavaScript Object and How Do You Create One?
An object in JavaScript is a collection of key-value pairs. The 'key' is the name of a piece of information (like 'firstName'), and the 'value' is the actual data stored under that name (like 'Sarah'). Together, each key-value pair is called a property.
The most common and readable way to create an object is with curly braces {}. This is called an object literal, and it's the go-to syntax for most JavaScript developers.
Inside the curly braces, you list your properties separated by commas. Each property is written as key: value. The key is usually written without quotes (unless it contains spaces or special characters), and the value can be any data type — a string, a number, a boolean, an array, or even another object.
Notice how grouping related data this way instantly makes your code more readable. Instead of six separate variables floating around, everything about a user lives in one place. That's the core win objects give you.
const when declaring objects unless you need to reassign the entire variable to a new object. const doesn't freeze the object — you can still change its properties freely. It just prevents you from accidentally pointing the variable at a completely different object later.Object() – it's slower and adds no benefit.Reading and Updating Object Properties — Dot vs Bracket Notation
Once you have an object, you need to get data out of it and put new data in. There are two ways to access a property: dot notation and bracket notation. Both do the same job — pick the right one for the situation.
Dot notation (object.propertyName) is cleaner and the one you'll use 90% of the time. Bracket notation (object['propertyName']) is more flexible — it lets you use a variable as the key, which is powerful when you don't know the property name until the code actually runs.
Updating a property is just as simple — you access it the same way and assign a new value with =. If the property doesn't exist yet, this same syntax creates it. There's no separate 'add property' command. Assignment does it all.
Deleting a property uses the delete keyword. It completely removes the key-value pair from the object, not just sets it to null. Use this with care — deleting properties can sometimes affect performance in JavaScript engines that optimise objects.
undefined. This is a common source of bugs. If you see undefined where you expected a real value, check your property name for typos first. Keys are case-sensitive, so bookListing.Title and bookListing.title are completely different.Looping Over an Object and Nesting Objects Inside Objects
Most real-world objects contain more properties than you'd want to type out one by one. JavaScript gives you a for...in loop specifically designed to iterate over every key in an object. On each iteration, the loop gives you the current key as a string, and you use bracket notation to get the value.
Objects can also be nested — meaning a property's value can itself be an object. This is how real data is structured. Think of a user profile that has an address: the address has a street, a city, and a postcode. It makes sense to group those three inside their own nested object rather than flattening everything into one level.
To access deeply nested properties, you just chain dot notation: user.address.city. Read it left to right — start at user, go into the address object, then grab the city property inside it.
Be careful with for...in — it can loop over inherited properties from the object's prototype chain in some situations. Using hasOwnProperty() is a defensive habit that guarantees you only touch properties you actually defined.
${userAccount[key]}), JavaScript converts it to the string [object Object] — not the full contents. To see nested object contents properly, use console.log(key, userAccount[key]) without a template literal, or use JSON.stringify(userAccount[key]) to convert it to a readable JSON string.Object.keys() or hasOwnProperty to avoid prototype pollution.Object.entries() with for...of.Object.keys() returns only own property names.Objects Are Reference Types — the Concept That Trips Everyone Up
Here's the thing that bites almost every beginner at some point: objects in JavaScript don't behave like numbers or strings when you copy or compare them.
With a number or string (primitive types), when you assign one variable to another, you get a true independent copy. Change one and the other is unaffected.
With objects, when you assign one variable to another, you don't copy the object — you copy the reference to it. Both variables now point at the exact same object in memory. So if you change a property through one variable, the other variable reflects that change too, because they're both looking at the same thing.
This also means two objects that look identical are NOT equal when you compare them with ===, because === checks whether they're the same reference (the same object in memory), not whether they have the same content.
To make a true shallow copy of an object, use the spread operator ({...originalObject}) or Object.assign(). For deeply nested objects, you need a deep clone, which JSON.parse(JSON.stringify(obj)) handles for simple cases.
{...obj}) for shallow copies and JSON.parse(JSON.stringify(obj)) for deep copies will impress any interviewer.Object Spreading and Merging – Combining Objects Safely
When you need to combine multiple objects into one, or create a new object from an existing one with modifications, the spread operator (...) is your best friend. Introduced in ES6, spread allows you to copy properties from one object into another elegantly.
For merging two objects, you can do: const merged = { ...objA, ...objB }. If both have the same property, the later source overwrites the earlier one. This is a shallow merge — nested objects are still shared references.
Object.assign() is the older alternative and does the same shallow merge. The spread syntax is generally preferred for readability.
Be careful with deep merging. A simple spread will not clone nested objects; they remain references. For a deep merge, you need to recursively merge or use a utility like Lodash's or _.merge()structuredClone() combined with spread.
structuredClone() for deep cloning, or manually deep copy nested levels.The Silent Mutation That Corrupted User Sessions
JSON.stringify()).- Always assume object assignment is a reference copy unless you explicitly copy the object.
- Use spread operator or structuredClone() when you need an independent snapshot.
- Treat object mutation as a shared state risk; prefer immutable patterns in production.
JSON.stringify())._.isEqual().Key takeaways
{ ...originalObject } (spread) to get a real shallow copy.undefined silentlyCommon mistakes to avoid
3 patternsTreating object assignment as a copy
const newObj = { ...existingObj } to create a proper shallow copy.Accessing a property that doesn't exist and assuming the code will error
undefined silently for missing properties, causing downstream bugs that are hard to trace.obj?.propertyName) for uncertain access, or check 'propertyName' in obj before accessing. Never assume a property exists unless you created it.Using `===` to compare two objects with identical content
{ name: 'Alex' } === { name: 'Alex' } evaluates to false because JavaScript compares references, not content.JSON.stringify(objA) === JSON.stringify(objB) for simple flat objects, or a library like Lodash's _.isEqual() for nested ones.Interview Questions on This Topic
What is the difference between dot notation and bracket notation in JavaScript, and when would you specifically choose bracket notation over dot notation?
obj.key) is cleaner and faster for property access when you know the exact key name at development time. Bracket notation (obj['key']) is necessary when the key name contains spaces or special characters, is a number, or is stored in a variable (dynamic key lookup). Bracket notation evaluates an expression inside the brackets, so it can also be used for computed properties. In production, prefer dot notation for readability and minor performance gains.Frequently Asked Questions
That's JS Basics. Mark it forged?
5 min read · try the examples if you haven't