JavaScript Objects
Master JavaScript objects with Mermaid diagrams, detailed explanations, and practical code examples covering creation, properties, methods, and advanced concepts
Objects are the fundamental building blocks of JavaScript. They store collections of key-value pairs and enable you to model real-world entities with properties and behaviors.
What is an Object?
An object is a collection of related data and functionality stored as key-value pairs. Think of it as a container that groups related information together.
// Simple object representing a person
const person = {
name: 'John Doe', // property
age: 30, // property
greet() { // method
console.log(`Hello, I'm ${this.name}`);
}
};
Object Fundamentals
graph TB
A[JavaScript Object] --> B[Properties]
A --> C[Methods]
A --> D[Reference Type]
B --> B1[Key-Value Pairs]
B --> B2[Any data type]
B --> B3[Dynamic addition]
C --> C1[Functions as values]
C --> C2[Access with this]
C --> C3[Object behavior]
D --> D1[Stored in heap]
D --> D2[Variable holds reference]
D --> D3[Mutable]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
style D fill:#9C27B0
Key Points:
- Properties: Data stored as key-value pairs (name, age, email)
- Methods: Functions that define object behavior (greet, calculate)
- Reference Type: Variables store memory address, not the actual object
- Dynamic: Can add, modify, or delete properties at runtime
- Flexible: Values can be any type (primitives, objects, functions)
Creating Objects
JavaScript provides multiple ways to create objects. Each method has its use cases.
Object Creation Methods
flowchart LR
A[Create Object] --> B[Object Literal]
A --> C[Constructor Function]
A --> D[Object.create]
A --> E[Class Syntax]
B --> B1[Most common]
B --> B2[Direct syntax]
C --> C1[new Object]
C --> C2[Custom constructor]
D --> D1[Prototype-based]
D --> D2[Inheritance]
E --> E1[ES6 plus syntax]
E --> E2[Syntactic sugar]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
style D fill:#9C27B0
style E fill:#00BCD4
Key Points:
- Object Literal: Simplest and most common
{key: value} - Constructor:
new Object()or custom constructors - Object.create(): Creates object with specific prototype
- Class: Modern ES6+ syntax for object creation
- Best Practice: Use object literals for simple objects
Code Examples: Creating Objects
// 1. Object Literal (Most Common)
const person = {
name: 'John Doe',
age: 30,
email: '[email protected]'
};
console.log(person.name); // 'John Doe'
// 2. new Object() Constructor
const person2 = new Object();
person2.name = 'Jane Smith';
person2.age = 25;
console.log(person2.age); // 25
// 3. Constructor Function (Pre-ES6)
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
return `Hello, I'm ${this.name}`;
};
}
const person3 = new Person('Bob', 35);
console.log(person3.greet()); // "Hello, I'm Bob"
// 4. Object.create() - Prototype-based
const personProto = {
greet() {
return `Hello, I'm ${this.name}`;
}
};
const person4 = Object.create(personProto);
person4.name = 'Alice';
console.log(person4.greet()); // "Hello, I'm Alice"
// 5. ES6 Class (Modern Approach)
class PersonClass {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, I'm ${this.name}`;
}
}
const person5 = new PersonClass('Charlie', 28);
console.log(person5.greet()); // "Hello, I'm Charlie"
Accessing Properties
You can access object properties using dot notation or bracket notation.
Property Access Methods
graph TB
A[Access Properties] --> B[Dot Notation]
A --> C[Bracket Notation]
B --> B1[obj.property]
B --> B2[Simple and readable]
B --> B3[Static property names]
C --> C1[obj property]
C --> C2[Dynamic property names]
C --> C3[Special characters allowed]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
Key Points:
- Dot Notation:
person.name- Clean, preferred for known properties - Bracket Notation:
person['name']- Required for dynamic keys or special characters - Dynamic Access: Use brackets with variables
person[key] - Computed Properties: Brackets allow expressions
person['first' + 'Name'] - Invalid Identifiers: Brackets needed for keys with spaces or special chars
Code Examples: Property Access
const user = {
firstName: 'John',
lastName: 'Doe',
age: 30,
'favorite color': 'blue', // Property with space
'123': 'numeric key' // Numeric string key
};
// Dot Notation (preferred for simple properties)
console.log(user.firstName); // 'John'
console.log(user.age); // 30
// Bracket Notation (required for special cases)
console.log(user['lastName']); // 'Doe'
console.log(user['favorite color']); // 'blue' (space in key)
console.log(user['123']); // 'numeric key'
// Dynamic Property Access
const propertyName = 'age';
console.log(user[propertyName]); // 30
// Computed Property Names
const prefix = 'first';
console.log(user[prefix + 'Name']); // 'John'
// Adding Properties
user.email = '[email protected]'; // Dot notation
user['phone'] = '555-0100'; // Bracket notation
// Updating Properties
user.age = 31;
user['firstName'] = 'Jonathan';
// Deleting Properties
delete user.phone;
console.log(user.phone); // undefined
Object Methods and this Keyword
Methods are functions stored as object properties. The this keyword refers to the object that called the method.
this Keyword Behavior
sequenceDiagram
participant Obj as Object
participant Method as Method
participant This as this
Obj->>Method: Call method
Method->>This: Refers to calling object
This->>Method: Access object properties
Method->>Obj: Return result
Note over This: this = object that called the method
Key Points:
- Context:
thisrefers to the object that called the method - Dynamic Binding: Value of
thisdetermined at call time - Arrow Functions: Don't have their own
this, inherit from parent - Global Context: In global scope,
thisrefers to window/global - Explicit Binding: Use call(), apply(), bind() to set
this
Code Examples: Methods and this
// Object with methods
const calculator = {
value: 0,
// Regular method - has its own 'this'
add(num) {
this.value += num;
return this; // Return this for method chaining
},
subtract(num) {
this.value -= num;
return this;
},
multiply(num) {
this.value *= num;
return this;
},
getValue() {
return this.value;
},
reset() {
this.value = 0;
return this;
}
};
// Using methods
calculator.add(10);
console.log(calculator.getValue()); // 10
// Method chaining
calculator
.reset()
.add(5)
.multiply(3)
.subtract(2);
console.log(calculator.getValue()); // 13
// Arrow functions vs regular functions
const person = {
name: 'John',
// Regular function - 'this' refers to person object
regularGreet() {
console.log(`Hello, I'm ${this.name}`);
},
// Arrow function - 'this' inherited from parent scope
arrowGreet: () => {
console.log(`Hello, I'm ${this.name}`); // 'this' is undefined
},
// Method that returns a function
delayedGreet() {
// Arrow function inherits 'this' from delayedGreet
setTimeout(() => {
console.log(`Hello, I'm ${this.name}`); // Works!
}, 1000);
}
};
person.regularGreet(); // "Hello, I'm John"
person.arrowGreet(); // "Hello, I'm undefined"
person.delayedGreet(); // "Hello, I'm John" (after 1 second)
Object References
Objects are reference types - variables store a reference (memory address) to the object, not the object itself.
Object Reference vs Value
flowchart TB
A[Variable Assignment] --> B{Primitive or Object?}
B -->|Primitive| C[Copy Value]
C --> D[Independent Variables]
B -->|Object| E[Copy Reference]
E --> F[Shared Object]
style C fill:#4CAF50
style D fill:#4CAF50
style E fill:#FF9800
style F fill:#FF9800
Key Points:
- Primitives: Copied by value, independent variables
- Objects: Copied by reference, variables point to same object
- Mutation: Changing object through one variable affects all references
- Comparison: Objects compared by reference, not content
- Cloning: Use spread
{...obj}or Object.assign() for shallow copy
Code Examples: References and Comparison
// Primitive values are copied
let a = 10;
let b = a; // b gets a copy of the value
b = 20;
console.log(a); // 10 (unchanged)
console.log(b); // 20
// Objects are referenced
const obj1 = { name: 'John', age: 30 };
const obj2 = obj1; // obj2 references the same object
obj2.age = 31;
console.log(obj1.age); // 31 (both point to same object)
console.log(obj2.age); // 31
// Object comparison (by reference)
const person1 = { name: 'John' };
const person2 = { name: 'John' };
const person3 = person1;
console.log(person1 === person2); // false (different objects)
console.log(person1 === person3); // true (same reference)
// Shallow copy with spread operator
const original = { name: 'John', age: 30 };
const copy = { ...original };
copy.age = 31;
console.log(original.age); // 30 (independent)
console.log(copy.age); // 31
// Shallow copy with Object.assign()
const copy2 = Object.assign({}, original);
copy2.name = 'Jane';
console.log(original.name); // 'John' (unchanged)
// Shallow copy limitation with nested objects
const user = {
name: 'John',
address: { city: 'NYC', zip: '10001' }
};
const userCopy = { ...user };
userCopy.address.city = 'LA';
console.log(user.address.city); // 'LA' (nested object still referenced!)
console.log(userCopy.address.city); // 'LA'
// Deep copy (fully independent)
const deepCopy = JSON.parse(JSON.stringify(user));
deepCopy.address.city = 'Chicago';
console.log(user.address.city); // 'LA' (unchanged)
console.log(deepCopy.address.city); // 'Chicago'
Object Methods
JavaScript provides built-in methods to work with objects.
Object Methods Overview
graph LR
A[Object Methods] --> B[Object.keys]
A --> C[Object.values]
A --> D[Object.entries]
A --> E[Object.assign]
A --> F[Object.freeze]
B --> B1[Returns array of keys]
C --> C1[Returns array of values]
D --> D1[Returns key-value pairs]
E --> E1[Copies properties]
F --> F1[Makes immutable]
style A fill:#2196F3
style B fill:#4CAF50
style C fill:#FF9800
style D fill:#9C27B0
style E fill:#00BCD4
style F fill:#F44336
Key Points:
- Object.keys(): Get array of property names
- Object.values(): Get array of property values
- Object.entries(): Get array of [key, value] pairs
- Object.assign(): Merge objects, shallow copy
- Object.freeze(): Prevent modifications (immutable)
Code Examples: Object Methods
const person = {
name: 'John',
age: 30,
city: 'New York',
email: '[email protected]'
};
// Object.keys() - Get all property names
const keys = Object.keys(person);
console.log(keys); // ['name', 'age', 'city', 'email']
// Iterate over keys
keys.forEach(key => {
console.log(`${key}: ${person[key]}`);
});
// Object.values() - Get all property values
const values = Object.values(person);
console.log(values); // ['John', 30, 'New York', '[email protected]']
// Object.entries() - Get key-value pairs
const entries = Object.entries(person);
console.log(entries);
// [['name', 'John'], ['age', 30], ['city', 'New York'], ['email', '[email protected]']]
// Convert entries back to object
const newObj = Object.fromEntries(entries);
console.log(newObj); // Same as person
// Object.assign() - Merge objects
const defaults = { theme: 'light', lang: 'en', notifications: true };
const userPrefs = { theme: 'dark', lang: 'es' };
const settings = Object.assign({}, defaults, userPrefs);
console.log(settings);
// { theme: 'dark', lang: 'es', notifications: true }
// Object.freeze() - Make immutable
const config = Object.freeze({
apiUrl: 'https://api.example.com',
apiKey: 'secret123'
});
config.apiKey = 'newkey'; // Fails silently (throws error in strict mode)
console.log(config.apiKey); // 'secret123' (unchanged)
// Object.seal() - Prevent adding/removing properties
const user = Object.seal({ name: 'John', age: 30 });
user.age = 31; // Allowed (modification)
user.email = 'test'; // Not allowed (addition)
delete user.name; // Not allowed (deletion)
console.log(user); // { name: 'John', age: 31 }
Destructuring and Optional Chaining
Modern JavaScript provides convenient syntax for extracting properties and safely accessing nested values.
Object Destructuring
flowchart LR
A[Object] --> B[Destructuring]
B --> C[Extract Properties]
C --> D[Individual Variables]
A --> A1[name: John, age: 30]
D --> D1[const name, age]
style A fill:#2196F3
style B fill:#FF9800
style C fill:#4CAF50
style D fill:#9C27B0
Key Points:
- Syntax:
const {name, age} = person - Renaming:
const {name: fullName} = person - Default Values:
const {city = 'Unknown'} = person - Nested:
const {address: {city}} = person - Rest:
const {name, ...rest} = person
Code Examples: Destructuring and Optional Chaining
// Basic destructuring
const user = { name: 'John', age: 30, city: 'NYC', email: '[email protected]' };
const { name, age } = user;
console.log(name); // 'John'
console.log(age); // 30
// Renaming variables
const { name: userName, age: userAge } = user;
console.log(userName); // 'John'
console.log(userAge); // 30
// Default values
const { country = 'USA', state = 'NY' } = user;
console.log(country); // 'USA' (default)
console.log(state); // 'NY' (default)
// Nested destructuring
const person = {
name: 'John',
address: {
city: 'NYC',
zip: '10001',
coordinates: { lat: 40.7128, lng: -74.0060 }
}
};
const { address: { city, zip, coordinates: { lat, lng } } } = person;
console.log(city); // 'NYC'
console.log(lat); // 40.7128
// Rest operator
const { name: personName, ...otherDetails } = user;
console.log(personName); // 'John'
console.log(otherDetails); // { age: 30, city: 'NYC', email: '...' }
// Function parameter destructuring
function greet({ name, age }) {
console.log(`Hello ${name}, you are ${age} years old`);
}
greet(user); // "Hello John, you are 30 years old"
// Optional Chaining (?.) - Safe property access
const data = {
user: {
profile: {
name: 'John',
settings: { theme: 'dark' }
}
}
};
// Without optional chaining (can throw error)
// console.log(data.user.profile.address.city); // Error!
// With optional chaining (returns undefined)
console.log(data?.user?.profile?.name); // 'John'
console.log(data?.user?.profile?.address?.city); // undefined (no error)
console.log(data?.user?.settings?.theme); // undefined
// Optional chaining with methods
const obj = {
method() {
return 'Hello';
}
};
console.log(obj.method?.()); // 'Hello'
console.log(obj.nonExistent?.()); // undefined (no error)
// Optional chaining with arrays
const arr = [1, 2, 3];
console.log(arr?.[0]); // 1
console.log(arr?.[10]); // undefined
Best Practices
- Use Object Literals: Simplest and most readable for creating objects
- Const for Objects: Use
constto prevent reassignment (object still mutable) - Meaningful Keys: Use descriptive property names (camelCase convention)
- Avoid Mutation: Consider immutability, use spread for copies
- Optional Chaining: Use
?.to safely access nested properties - Destructuring: Extract properties for cleaner code
- Method Shorthand: Use
method() {}instead ofmethod: function() {} - Computed Properties: Use
[expression]for dynamic keys
// Good practices example
const createUser = (name, age, email) => ({
name,
age,
email,
createdAt: new Date(),
// Method shorthand
getInfo() {
return `${this.name} (${this.age})`;
},
// Computed property
[`is${age >= 18 ? 'Adult' : 'Minor'}`]: true
});
const user = createUser('John', 30, '[email protected]');
console.log(user.getInfo()); // "John (30)"
console.log(user.isAdult); // true