Skip to main content

Module 7: Objects

Objects are the fundamental data structure in JavaScript for storing collections of key-value pairs and complex entities.


1. Creating Objects

1.1 Object Literals

const emptyObject = {};

const user = {
name: 'John',
age: 30,
email: 'john@example.com'
};

1.2 Object Constructor

const user = new Object();
user.name = 'John';
user.age = 30;

1.3 Object.create()

const personPrototype = {
greet() {
return `Hello, I'm ${this.name}`;
}
};

const user = Object.create(personPrototype);
user.name = 'John';
console.log(user.greet()); // Hello, I'm John
Best Practice

Prefer object literals {} for creating objects.


2. Accessing Properties

2.1 Dot Notation

const user = { name: 'John', age: 30 };

user.name; // 'John'
user.age; // 30

2.2 Bracket Notation

const user = { name: 'John', age: 30 };

user['name']; // 'John'
user['age']; // 30

// Dynamic property access
const prop = 'name';
user[prop]; // 'John'

// Property names with spaces or special chars
const obj = { 'first-name': 'John' };
obj['first-name']; // 'John'

2.3 Optional Chaining (ES2020)

const user = {
name: 'John',
address: {
city: 'New York'
}
};

user?.address?.city; // 'New York'
user?.address?.zip; // undefined (no error)
user?.contact?.phone; // undefined (no error)

3. Adding & Modifying Properties

const user = { name: 'John' };

// Add property
user.age = 30;
user['email'] = 'john@example.com';

// Modify property
user.name = 'Jane';

// Computed property names (ES6)
const propName = 'role';
const user2 = {
name: 'John',
[propName]: 'admin'
};

4. Deleting Properties

const user = {
name: 'John',
age: 30,
temp: 'value'
};

delete user.temp; // true
delete user.nonexistent; // true (no error)

// Set to undefined (not recommended)
user.age = undefined; // Property still exists

5. Checking Properties

const user = { name: 'John', age: 30 };

// in operator
'name' in user; // true
'email' in user; // false

// hasOwnProperty()
user.hasOwnProperty('name'); // true
user.hasOwnProperty('toString'); // false (inherited)

// Check for undefined
user.name !== undefined; // true

6. Iterating Over Objects

6.1 for...in

const user = { name: 'John', age: 30, city: 'New York' };

for (const key in user) {
console.log(key, user[key]);
}

6.2 Object.keys()

const keys = Object.keys(user); // ['name', 'age', 'city']

keys.forEach(key => {
console.log(key, user[key]);
});

6.3 Object.values()

const values = Object.values(user); // ['John', 30, 'New York']

6.4 Object.entries()

const entries = Object.entries(user);
// [['name', 'John'], ['age', 30], ['city', 'New York']]

for (const [key, value] of entries) {
console.log(key, value);
}

7. Object Methods

const calculator = {
value: 0,
add(n) {
this.value += n;
return this;
},
subtract(n) {
this.value -= n;
return this;
},
multiply(n) {
this.value *= n;
return this;
},
getValue() {
return this.value;
}
};

// Method chaining
calculator.add(5).multiply(2).subtract(3).getValue(); // 7

8. Shorthand Properties & Methods (ES6)

const name = 'John';
const age = 30;

// Old way
const user1 = {
name: name,
age: age
};

// Shorthand
const user2 = { name, age };

// Method shorthand
const obj = {
// Old way
greet: function() {
return 'Hello';
},
// Shorthand
hello() {
return 'Hello';
}
};

9. Object Destructuring (ES6)

const user = {
name: 'John',
age: 30,
email: 'john@example.com'
};

// Basic destructuring
const { name, age } = user;

// Rename variables
const { name: userName, age: userAge } = user;

// Default values
const { name, role = 'user' } = user;

// Rest operator
const { name, ...rest } = user;
// rest = { age: 30, email: 'john@example.com' }

// Nested destructuring
const user2 = {
name: 'John',
address: {
city: 'New York',
zip: '10001'
}
};

const { address: { city, zip } } = user2;

10. Copying Objects

10.1 Shallow Copy

const original = { a: 1, b: 2 };

// Spread operator
const copy1 = { ...original };

// Object.assign()
const copy2 = Object.assign({}, original);

// Add properties while copying
const copy3 = { ...original, c: 3 };

10.2 Deep Copy

const original = {
name: 'John',
address: { city: 'New York' }
};

// JSON method (limitations: no functions, dates, undefined)
const deepCopy = JSON.parse(JSON.stringify(original));

// structuredClone (modern)
const deepCopy2 = structuredClone(original);

// Manual deep clone
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;
}

11. Merging Objects

const defaults = { theme: 'light', language: 'en' };
const userSettings = { theme: 'dark' };

// Spread operator (later properties override)
const settings = { ...defaults, ...userSettings };
// { theme: 'dark', language: 'en' }

// Object.assign()
const settings2 = Object.assign({}, defaults, userSettings);

12. Object Property Descriptors

const user = {};

Object.defineProperty(user, 'name', {
value: 'John',
writable: false, // Cannot be changed
enumerable: true, // Shows in loops
configurable: false // Cannot be deleted or reconfigured
});

// Get descriptor
const descriptor = Object.getOwnPropertyDescriptor(user, 'name');

// Define multiple properties
Object.defineProperties(user, {
age: { value: 30, writable: true },
email: { value: 'john@example.com', writable: true }
});

13. Getters and Setters

const user = {
firstName: 'John',
lastName: 'Doe',

get fullName() {
return `${this.firstName} ${this.lastName}`;
},

set fullName(value) {
[this.firstName, this.lastName] = value.split(' ');
}
};

user.fullName; // 'John Doe'
user.fullName = 'Jane Smith';
user.firstName; // 'Jane'

14. Object.freeze() & Object.seal()

// freeze - cannot add, delete, or modify properties
const user = Object.freeze({ name: 'John' });
user.name = 'Jane'; // Silently fails (strict mode: error)
user.age = 30; // Silently fails

// seal - cannot add or delete, but can modify
const user2 = Object.seal({ name: 'John' });
user2.name = 'Jane'; // ✅ Works
user2.age = 30; // ❌ Fails

// Check if frozen/sealed
Object.isFrozen(user); // true
Object.isSealed(user2); // true

15. this Keyword

const user = {
name: 'John',
greet() {
console.log(`Hello, I'm ${this.name}`);
},
greetArrow: () => {
console.log(`Hello, I'm ${this.name}`); // ❌ undefined
}
};

user.greet(); // Works: this = user
const greetFn = user.greet;
greetFn(); // ❌ this = undefined (strict mode)

// Bind this
const boundGreet = user.greet.bind(user);
boundGreet(); // Works

16. Object Comparison

// Objects are compared by reference
const obj1 = { a: 1 };
const obj2 = { a: 1 };
const obj3 = obj1;

obj1 === obj2; // false (different references)
obj1 === obj3; // true (same reference)

// Deep equality (manual)
function deepEqual(obj1, obj2) {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);

if (keys1.length !== keys2.length) return false;

for (const key of keys1) {
const val1 = obj1[key];
const val2 = obj2[key];
const areObjects = typeof val1 === 'object' && typeof val2 === 'object';

if (areObjects) {
if (!deepEqual(val1, val2)) return false;
} else if (val1 !== val2) {
return false;
}
}

return true;
}

Summary

In this module, you learned:

  • ✅ Creating and accessing object properties
  • ✅ Object methods and this keyword
  • ✅ Destructuring and shorthand syntax
  • ✅ Copying and merging objects
  • ✅ Property descriptors, getters, and setters
  • ✅ Object.freeze() and Object.seal()
  • ✅ Iterating over objects
  • ✅ Object comparison
Next Steps

In Module 8, you'll learn about Strings – essential for text manipulation.


Practice Exercises

  1. Create a user object with nested address
  2. Implement object destructuring in function parameters
  3. Build a calculator object with method chaining
  4. Deep clone an object without JSON methods
  5. Create getters and setters for computed properties
  6. Implement a function to merge multiple objects
  7. Use Object.entries() to transform an object
  8. Compare two objects for deep equality

Additional Resources