HomeBytesheetsRoadmapsUI TemplatesUI ToolsStack Discussion
5 Topics
Chapter•85 Minutes

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.

Inspecting Property Descriptors
const user = {
  name: 'Suriya'
};

console.log(Object.getOwnPropertyDescriptor(user, 'name'));
💡 The descriptor reveals attributes such as writable, enumerable, and configurable in addition to the property's value.
Key Takeaways
  • Object properties have descriptors.
  • Property keys are strings or symbols.
  • Object literals are convenient syntax over a richer property model.
Knowledge Check

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
Key Takeaways
  • Prototype lookup is property delegation.
  • The chain ends at null.
  • Class syntax ultimately relies on prototypes.
Knowledge Check

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.

Shared Prototype Method
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);
💡 Both instances resolve greet through User.prototype, so they reference the same function.
Key Takeaways
  • Prototype methods can be shared by instances.
  • Instance-created methods create separate function objects.
  • Prototype delegation can reduce duplication.
Knowledge Check

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 and Prototype Relationship
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);
💡 The greet method is defined on User.prototype. The instance resolves it through the prototype chain.
Key Takeaways
  • Classes are syntax built around JavaScript's prototype model.
  • Class methods normally live on the prototype.
  • new creates an instance and establishes the prototype relationship.
Knowledge Check

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.

Private State
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);
💡 The balance field is private to the class body. External code can use the public getter but cannot directly access #balance.
Key Takeaways
  • 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.
Knowledge Check

Which syntax defines a JavaScript private class field?