Chapter 7: The Object Kingdom Chronicles
· 12 min read
Chapter 7: The Object Kingdom Chronicles
Objects are the heart of JavaScript Land. Everything else either is an object or can become one.
Object Creation and Access
// Object literal syntax
let wizard = {
name: "Gandalf",
age: 2019,
staff: "wooden",
spells: ["fireball", "lightning", "heal"],
// Methods
castSpell: function(spellName) {
return `${this.name} casts ${spellName}!`;
},
// ES6 method shorthand
meditate() {
return `${this.name} is meditating...`;
}
};
// Property access
console.log(wizard.name); // Dot notation
console.log(wizard["age"]); // Bracket notation
console.log(wizard.spells[0]); // Accessing array property
// Dynamic property access
let prop = "staff";
console.log(wizard[prop]); // "wooden"
// Computed property names
let skill = "magic";
let level = "expert";
let mage = {
name: "Merlin",
[skill]: level, // Computed property: magic: "expert"
[`${skill}Level`]: 95 // magicLevel: 95
};
Object Destructuring - The Property Extractor
let hero = {
name: "Wonder Woman",
realName: "Diana Prince",
powers: ["super strength", "flight", "lasso of truth"],
team: "Justice League"
};
// Basic destructuring
let { name, powers } = hero;
console.log(name); // "Wonder Woman"
console.log(powers); // ["super strength", "flight", "lasso of truth"]
// Renaming variables
let { realName: secretIdentity } = hero;
console.log(secretIdentity); // "Diana Prince"
// Default values
let { weakness = "none", team } = hero;
console.log(weakness); // "none"
console.log(team); // "Justice League"
// Nested destructuring
let villain = {
name: "Joker",
base: {
location: "Arkham Asylum",
security: "maximum"
}
};
let { base: { location, security } } = villain;
console.log(location); // "Arkham Asylum"
console.log(security); // "maximum"
// Rest in object destructuring
let { name: heroName, ...otherProps } = hero;
console.log(heroName); // "Wonder Woman"
console.log(otherProps); // { realName: "Diana Prince", powers: [...], team: "Justice League" }
Object Methods and this Context
let calculator = {
result: 0,
add(num) {
this.result += num;
return this; // Return this for method chaining
},
multiply(num) {
this.result *= num;
return this;
},
reset() {
this.result = 0;
return this;
},
getValue() {
return this.result;
}
};
// Method chaining
let finalResult = calculator.add(5).multiply(3).add(2).getValue();
console.log(finalResult); // 17
// The 'this' binding can be tricky
let obj = {
name: "Alice",
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
obj.greet(); // "Hello, I'm Alice"
// Lost 'this' context
let greetFunction = obj.greet;
greetFunction(); // "Hello, I'm undefined" (in strict mode) or global name
// Solutions: bind, call, apply
let boundGreet = obj.greet.bind(obj);
boundGreet(); // "Hello, I'm Alice"
obj.greet.call(obj); // "Hello, I'm Alice"
obj.greet.apply(obj); // "Hello, I'm Alice"
Object Manipulation Techniques
// Object.keys, Object.values, Object.entries
let book = {
title: "JavaScript: The Good Parts",
author: "Douglas Crockford",
year: 2008,
pages: 172
};
console.log(Object.keys(book)); // ["title", "author", "year", "pages"]
console.log(Object.values(book)); // ["JavaScript: The Good Parts", "Douglas Crockford", 2008, 172]
console.log(Object.entries(book)); // [["title", "JavaScript: The Good Parts"], ...]
// Object.assign - shallow copy and merge
let defaults = { theme: "dark", language: "en" };
let userPrefs = { theme: "light", fontSize: 14 };
let settings = Object.assign({}, defaults, userPrefs);
console.log(settings); // { theme: "light", language: "en", fontSize: 14 }
// Spread operator with objects (ES6+)
let newSettings = { ...defaults, ...userPrefs, autoSave: true };
console.log(newSettings); // { theme: "light", language: "en", fontSize: 14, autoSave: true }
// Property descriptors
Object.defineProperty(book, 'isbn', {
value: '978-0596517748',
writable: false, // Can't be changed
enumerable: true, // Shows up in for...in loops
configurable: false // Can't be deleted or redefined
});
// Check if property exists
console.log('title' in book); // true
console.log(book.hasOwnProperty('title')); // true
console.log('toString' in book); // true (inherited)
console.log(book.hasOwnProperty('toString')); // false (inherited)
Advanced Object Patterns
Factory Functions and Object Creation
// Factory function pattern
function createPerson(name, age) {
return {
name,
age,
greet() {
return `Hi, I'm ${this.name} and I'm ${this.age} years old`;
},
haveBirthday() {
this.age++;
return `Happy birthday! Now ${this.age} years old`;
}
};
}
let john = createPerson("John", 25);
console.log(john.greet()); // "Hi, I'm John and I'm 25 years old"
// Constructor function pattern
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
return `Hi, I'm ${this.name}`;
};
let jane = new Person("Jane", 30);
console.log(jane.greet()); // "Hi, I'm Jane"
Object.create and Prototypal Inheritance
// Create object with specific prototype
let animal = {
type: "unknown",
makeSound() {
return "Some generic sound";
}
};
let dog = Object.create(animal);
dog.type = "canine";
dog.makeSound = function() {
return "Woof!";
};
console.log(dog.makeSound()); // "Woof!"
console.log(dog.__proto__ === animal); // true
// Null prototype object
let pureObject = Object.create(null);
console.log(pureObject.toString); // undefined (no inherited methods)
Getters and Setters
let user = {
firstName: "John",
lastName: "Doe",
// Getter
get fullName() {
return `${this.firstName} ${this.lastName}`;
},
// Setter
set fullName(value) {
[this.firstName, this.lastName] = value.split(' ');
},
// Computed property with validation
_age: 0,
get age() {
return this._age;
},
set age(value) {
if (value < 0 || value > 150) {
throw new Error("Invalid age");
}
this._age = value;
}
};
console.log(user.fullName); // "John Doe"
user.fullName = "Jane Smith";
console.log(user.firstName); // "Jane"
console.log(user.lastName); // "Smith"
Object Freezing and Sealing
// Object.freeze - no modifications allowed
let frozenObj = Object.freeze({
name: "Frozen",
nested: { value: 42 }
});
frozenObj.name = "Changed"; // Silently fails (error in strict mode)
frozenObj.newProp = "New"; // Silently fails
delete frozenObj.name; // Silently fails
frozenObj.nested.value = 100; // Works! (shallow freeze)
// Object.seal - no adding/deleting, but can modify
let sealedObj = Object.seal({
name: "Sealed",
value: 42
});
sealedObj.name = "Modified"; // Works
sealedObj.newProp = "New"; // Silently fails
delete sealedObj.value; // Silently fails
// Object.preventExtensions - no new properties
let obj = { existing: true };
Object.preventExtensions(obj);
obj.existing = false; // Works
obj.newProp = "new"; // Silently fails
Common Object Pitfalls
// Object comparison
let obj1 = { a: 1 };
let obj2 = { a: 1 };
console.log(obj1 === obj2); // false (different references)
console.log(obj1 == obj2); // false
// Shallow vs Deep copy
let original = {
name: "Original",
nested: { value: 42 }
};
let shallowCopy = { ...original };
shallowCopy.nested.value = 100;
console.log(original.nested.value); // 100 (nested object is shared!)
// Deep copy with JSON (limited)
let deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.nested.value = 200;
console.log(original.nested.value); // 100 (truly independent)
// But JSON method has limitations
let complexObj = {
date: new Date(),
func: () => "hello",
undef: undefined,
symbol: Symbol("sym")
};
let jsonCopy = JSON.parse(JSON.stringify(complexObj));
console.log(jsonCopy); // { date: "2023-...", func/undef/symbol missing }
Performance Considerations
// Use object literals when possible
let fast = { a: 1, b: 2 }; // Optimized by engine
// Avoid delete operator in hot code
let obj = { a: 1, b: 2, c: 3 };
// delete obj.b; // Slow - changes object shape
obj.b = undefined; // Faster alternative
// Hidden classes optimization
// Keep object shape consistent
function Point(x, y) {
this.x = x;
this.y = y;
}
// All Points have same shape - optimized
let p1 = new Point(1, 2);
let p2 = new Point(3, 4);
// Avoid changing shape after creation
// p1.z = 5; // De-optimizes the hidden class
Next Chapter: Chapter 8: The Scope and Closure Mysteries
Previous Chapter: Chapter 6: The Array Adventures
Table of Contents: JavaScript Guide