Objects, Prototypes, Classes, and Inheritance
Understand JavaScript's object model instead of treating classes as traditional class-based inheritance. Learn property descriptors, prototype chains, constructors, and class syntax.
Objects and Property Keys
JavaScript objects are collections of properties. Property keys are strings or symbols. When a non-symbol key is used, JavaScript generally converts it to a string. Properties have more than just values: they can have descriptors such as writable, enumerable, and configurable.
This descriptor model explains behavior that ordinary object literal syntax hides.
const user = {
name: 'Suriya'
};
console.log(Object.getOwnPropertyDescriptor(user, 'name'));- Object properties have descriptors.
- Property keys are strings or symbols.
- Object literals are convenient syntax over a richer property model.
Which of these can be an object property key?
The Prototype Chain
Every ordinary JavaScript object has an internal [[Prototype]] link, which can point to another object or null. When a property is not found directly on an object, JavaScript searches its prototype, then that prototype's prototype, and so on.
This delegation chain is JavaScript's fundamental inheritance mechanism. Class syntax is built on top of this system.
- Prototype lookup is property delegation.
- The chain ends at null.
- Class syntax ultimately relies on prototypes.
What happens when a property is not found directly on an object?
Prototype Methods vs Instance Methods
Putting a method on a prototype allows all instances sharing that prototype to access the same function. Defining a function separately on every instance creates separate function objects and can increase memory usage.
This distinction matters when creating large numbers of objects or designing reusable object abstractions.
function User(name) {
this.name = name;
}
User.prototype.greet = function () {
return `Hello ${this.name}`;
};
const a = new User('A');
const b = new User('B');
console.log(a.greet === b.greet);- Prototype methods can be shared by instances.
- Instance-created methods create separate function objects.
- Prototype delegation can reduce duplication.
Why can prototype methods be memory-efficient for many instances?
JavaScript Classes
Classes provide cleaner syntax for creating constructor/prototype relationships. A class constructor runs when an instance is created with new. Methods defined in the class body are placed on the prototype rather than copied as own properties onto every instance.
Classes also support extends, super, private fields using #, static members, getters, and setters.
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello ${this.name}`;
}
}
const user = new User('Suriya');
console.log(user.greet());
console.log(User.prototype.greet === user.greet);- Classes are syntax built around JavaScript's prototype model.
- Class methods normally live on the prototype.
newcreates an instance and establishes the prototype relationship.
Where is a normal method defined in a JavaScript class placed?
Getters, Setters, and Private Fields
Getters and setters allow property-like syntax around custom behavior. Private class fields use the # syntax and are enforced by the language, unlike naming conventions such as _value.
Private fields cannot be accessed with normal property syntax from outside the class. This provides stronger encapsulation than convention-based private properties.
class BankAccount {
#balance = 0;
deposit(amount) {
if (amount <= 0) throw new Error('Invalid amount');
this.#balance += amount;
}
get balance() {
return this.#balance;
}
}
const account = new BankAccount();
account.deposit(100);
console.log(account.balance);- Getters and setters provide controlled property access.
- Private fields use
#and are enforced by the language. - Encapsulation can protect invariants such as valid account balances.
Which syntax defines a JavaScript private class field?