JavaScript tutorials  /  Objects in JavaScript
Chapter 11 · JavaScript

Objects in JavaScript

An object in JavaScript is a non-primitive data type used to store collections of related data as key-value pairs, where keys are strings (or Symbols) and values can be any data type, including numbers, strings, arrays, functions, or even other objects. Objects allow developers to group related properties and behaviors (methods) together, forming the foundation of object-oriented programming in JavaScript.

Imagine a real-world filing folder labeled 'Employee Record.' Inside this folder, you have different labeled sections like 'Name,' 'Age,' 'Department,' and 'Salary,' each holding a specific piece of information. A JavaScript object works the same way — it's a container that holds related pieces of information (properties) under descriptive labels (keys), so instead of managing many separate variables, you keep everything organized together in one structured unit.

Consider a food delivery app like Zomato displaying a restaurant's details on its page. Instead of storing the restaurant's name, rating, cuisine type, delivery time, and address in five separate variables, developers store them together as a single object: const restaurant = { name: 'Spice Villa', rating: 4.3, cuisine: 'North Indian', deliveryTime: '30-35 mins', address: 'MG Road, Pune' }. This makes it much easier to pass the entire restaurant's data around the application as one unit — for example, sending it to a card component to render on the screen, or storing an array of many such restaurant objects to display search results.

Objects are essential because real-world data is naturally structured and related, and objects let developers model this structure directly in code rather than managing many disconnected variables. They enable grouping of data and behavior together, support key features like JSON data exchange with APIs, allow dynamic addition and removal of properties, and form the basis for more advanced concepts like classes, prototypes, and object-oriented design patterns, making code more organized, readable, and maintainable.

  • Object Literal: The most common way to create an object, using curly braces {} with key-value pairs defined directly, such as const person = { name: 'Ravi', age: 25 };
  • Object Created with the new Object() Constructor: An object created using the built-in Object constructor function, such as const person = new Object(); person.name = 'Ravi';, which is less common but functionally equivalent to a literal.
  • Object Created Using a Constructor Function: An object created by invoking a custom constructor function with the new keyword, allowing multiple similar objects to be created from the same blueprint, such as function Person(name) { this.name = name; } and const p1 = new Person('Amit');
  • Object Created Using Object.create(): An object created with a specified prototype object, using Object.create(protoObj), giving fine-grained control over the prototype chain without using constructor functions or classes.
  • Object Created Using ES6 Class: An object created by instantiating a class defined with the class keyword, which provides a more structured, readable syntax for creating objects with shared methods via the prototype, such as class Person { constructor(name) { this.name = name; } } and const p = new Person('Meena');
// Object literal syntax const objectName = { key1: value1, key2: value2, methodName: function() { // method body } }; // Accessing properties objectName.key1; // dot notation objectName['key2']; // bracket notation // Adding or updating a property objectName.newKey = newValue; // Deleting a property delete objectName.key1;
Suppose you're building a user profile feature for a social media app where each user has a name, email, age, list of interests, and a settings sub-section containing notification preferences and privacy settings. Managing all of this as separate individual variables (userName, userEmail, userAge, userInterests, userNotificationSettings, and so on) would quickly become unmanageable, especially when you need to pass this data to different functions or store multiple users. How do you group all of this related data into a single, organized, and easily accessible structure?
Creating and Accessing an Object Literal
A basic object representing a user profile, accessed using both dot notation and bracket notation.
JavaScript
const user = { name: 'Priya', age: 27, email: 'priya@example.com' }; console.log(user.name); console.log(user['email']);
Priya priya@example.com
The user object stores three related properties: name, age, and email. The name property is accessed using dot notation (user.name), while email is accessed using bracket notation (user['email']), which is useful when the property name is dynamic or contains special characters.
Adding, Updating, and Deleting Object Properties
Demonstrating how object properties can be dynamically modified after the object has been created.
JavaScript
const product = { name: 'Laptop', price: 55000 }; product.stock = 10; product.price = 52000; delete product.stock; console.log(product);
{ name: 'Laptop', price: 52000 }
A new stock property is added to the product object, the price property is updated to a new value, and then stock is removed using the delete operator. This shows that JavaScript objects are mutable and can be freely modified after creation, unlike some other data structures.
Object with Methods and 'this' Keyword
An object containing a method that uses the 'this' keyword to access other properties of the same object.
JavaScript
const employee = { firstName: 'Rahul', lastName: 'Verma', getFullName: function() { return `${this.firstName} ${this.lastName}`; } }; console.log(employee.getFullName());
Rahul Verma
The getFullName method uses the 'this' keyword to refer to the employee object itself, allowing it to access firstName and lastName from within the method. Since getFullName is called as employee.getFullName(), 'this' correctly refers to employee.
Iterating Over Object Properties and Using Object Methods
Using a for...in loop and Object.keys(), Object.values(), and Object.entries() to work with an object's data.
JavaScript
const car = { brand: 'Toyota', model: 'Fortuner', year: 2023 }; for (const key in car) { console.log(`${key}: ${car[key]}`); } console.log(Object.keys(car)); console.log(Object.values(car));
brand: Toyota model: Fortuner year: 2023 [ 'brand', 'model', 'year' ] [ 'Toyota', 'Fortuner', 2023 ]
The for...in loop iterates over every enumerable property key in the car object, printing each key-value pair. Object.keys() returns an array of just the property names, while Object.values() returns an array of just the corresponding values, both commonly used for transforming or displaying object data.
  • Confusing Object Equality with Reference Comparison: Developers often expect two objects with identical properties to be considered equal using ===, but object comparisons in JavaScript check reference equality, not structural equality. For example, {name: 'A'} === {name: 'A'} evaluates to false because they are two different objects in memory, even though their contents look the same, which surprises many beginners.
  • Accidentally Mutating an Object Passed by Reference: Since objects are passed by reference in JavaScript, modifying an object inside a function also affects the original object outside the function, which can lead to unintended side effects. For example, passing a user object to a function that changes user.age directly mutates the original object, which may not be the intended behavior if a fresh copy was expected.
  • Using Bracket Notation Incorrectly with Dynamic Keys: A common mistake is forgetting to use bracket notation when accessing a property with a dynamic key stored in a variable, such as writing obj.key instead of obj[key], which looks for a literal property named 'key' instead of the value stored in the key variable, leading to undefined results.
  • Forgetting that for...in Also Iterates Inherited Properties: The for...in loop iterates over all enumerable properties, including those inherited through the prototype chain, not just the object's own properties. Without using hasOwnProperty() to filter, this can lead to unexpected properties appearing in the loop, especially when working with objects that have custom prototypes.
  • Shallow Copying Nested Objects and Expecting a Deep Copy: Using techniques like the spread operator ({...obj}) or Object.assign() creates only a shallow copy, meaning nested objects or arrays within the original object are still shared by reference. Modifying a nested property in the 'copied' object unexpectedly also changes the original object, since only the top-level properties were actually copied.
  • Use Object Literals for Simple, One-Off Objects: For creating simple, single-use objects, prefer the concise object literal syntax ({ key: value }) over the new Object() constructor, since it's more readable, performs better, and is the idiomatic JavaScript approach favored across the community.
  • Use hasOwnProperty() or Object.hasOwn() When Iterating: When looping through an object's properties with for...in, always check obj.hasOwnProperty(key) or use the newer Object.hasOwn(obj, key) to ensure only the object's own properties are processed, avoiding unintended inherited properties from the prototype chain.
  • Use the Spread Operator or structuredClone() for Copying Objects: Use the spread operator ({...obj}) for quick shallow copies, but for deep copying nested objects, use structuredClone(obj) (supported in modern environments) or a well-tested deep-clone utility, rather than manually writing recursive copy logic or relying on JSON.parse(JSON.stringify(obj)), which fails for functions, dates, and undefined values.
  • Use Object Destructuring for Cleaner Property Access: Instead of repeatedly accessing multiple properties using dot notation, use object destructuring, such as const { name, age } = user;, to extract multiple values in a single, readable line, especially useful in function parameters and when working with API response data.
  • Prefer Immutability When Managing Application State: In frameworks like React or Redux, avoid directly mutating state objects; instead, create new objects with updated values using the spread operator or Object.assign(), such as const updatedUser = { ...user, age: 28 };, since direct mutation can cause bugs with change detection and unpredictable UI behavior.
What is the difference between primitive data types and objects in JavaScript?
Primitive data types (string, number, boolean, null, undefined, symbol, bigint) are immutable and stored directly by value, meaning each variable holds its own independent copy of the data. Objects, on the other hand, are reference types, meaning variables store a reference (memory address) to the object rather than the actual data, so assigning an object to another variable or passing it to a function shares the same underlying object rather than creating a copy.
What is the difference between dot notation and bracket notation for accessing object properties?
Dot notation (obj.property) is more concise and readable but requires the property name to be a valid identifier known at write-time. Bracket notation (obj['property']) is more flexible because it allows accessing properties using a dynamic value stored in a variable, property names that include spaces or special characters, or property names that are only known at runtime, such as obj[variableName].
Explain the difference between shallow copy and deep copy of an object, with examples.
A shallow copy duplicates only the top-level properties of an object, but nested objects or arrays within it remain shared by reference with the original, so modifying a nested value in the copy also affects the original. Techniques like the spread operator ({...obj}) or Object.assign({}, obj) create shallow copies. A deep copy duplicates the object and all nested objects/arrays recursively, creating a completely independent structure, achievable using structuredClone(obj) or a recursive deep-clone function, ensuring changes to the copy never affect the original.
What is the prototype chain in JavaScript and how does it relate to objects?
Every JavaScript object has an internal link to another object called its prototype, forming a chain. When accessing a property or method on an object, JavaScript first checks the object's own properties, and if not found, it looks up the prototype chain until it finds the property or reaches the end of the chain (null). This mechanism enables inheritance, allowing objects to share methods and properties defined on their prototypes without duplicating them on every instance.
How does the 'this' keyword behave differently inside a regular object method versus an arrow function defined as an object property?
Inside a regular function used as an object method, 'this' refers to the object the method is called on, determined dynamically at call time. However, if an arrow function is used as an object property instead, 'this' does not refer to the object; instead, it inherits 'this' from the surrounding lexical scope where the object literal was defined (often the global object or undefined in strict mode), which is a common source of bugs when developers mistakenly use arrow functions for object methods that need to access 'this'.
Create an object named book with properties title, author, and price, then log its title using dot notation and its price using bracket notation.
const book = { title: '1984', author: 'George Orwell', price: 399 }; console.log(book.title); // '1984' console.log(book['price']); // 399
Write code to add a new property 'inStock' with value true to an existing object named item, then delete its 'discount' property.
const item = { name: 'Headphones', price: 1999, discount: 10 }; item.inStock = true; delete item.discount; console.log(item); // { name: 'Headphones', price: 1999, inStock: true }
Create an object named circle with a radius property and a method calculateArea that returns the area using 'this' to access the radius.
const circle = { radius: 7, calculateArea: function() { return Math.PI * this.radius * this.radius; } }; console.log(circle.calculateArea()); // 153.93804002589985
Write a function named mergeObjects that takes two objects and returns a new object combining both, without mutating either original object.
function mergeObjects(obj1, obj2) { return { ...obj1, ...obj2 }; } const defaults = { theme: 'light', fontSize: 14 }; const userPrefs = { fontSize: 18 }; console.log(mergeObjects(defaults, userPrefs)); // { theme: 'light', fontSize: 18 }
Write a function named deepClone that creates a deep copy of a nested object without using structuredClone(), then demonstrate that modifying the clone does not affect the original.
function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; const clone = Array.isArray(obj) ? [] : {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { clone[key] = deepClone(obj[key]); } } return clone; } const original = { name: 'Sara', address: { city: 'Delhi', pin: 110001 } }; const copy = deepClone(original); copy.address.city = 'Mumbai'; console.log(original.address.city); // 'Delhi' console.log(copy.address.city); // 'Mumbai'

Objects are a fundamental data structure in JavaScript used to group related data and behavior together as key-value pairs. They can be created using object literals, constructor functions, Object.create(), or ES6 classes, and support dynamic addition, modification, and deletion of properties. Understanding how objects are passed by reference, how the 'this' keyword behaves within methods, the difference between shallow and deep copying, and how the prototype chain enables inheritance are all essential concepts for working effectively with objects. Mastering objects is a critical step toward understanding more advanced JavaScript topics like classes, prototypes, and object-oriented design patterns.

© 2026 CompileX. Maintained by Aditya Kumar Sharma.