Tutorials Logic, IN info@tutorialslogic.com

Classes Objects in JavaScript ES6 OOP

JavaScript Class Model

JavaScript classes provide strict constructor, prototype, field, private-name, static, and inheritance semantics over the language object model. They are useful when instances share behavior and preserve durable invariants, but they are not the right container for every record or function.

Sound class design keeps construction valid, receiver ownership explicit, async creation in factories, inheritance contracts narrow, external capabilities injected, and tests focused on public outcomes.

Classes in JavaScript

A JavaScript class defines a constructor, instance methods, static members, fields, and inheritance syntax for creating related objects. Class behavior is implemented through JavaScript's prototype system, so method lookup and inheritance still follow the prototype chain.

A class can contain a constructor() method for initializing values, as well as instance methods that are available on every object created from that class. When we create an object using the new keyword, JavaScript builds a new instance and binds this to that object.

The constructor runs automatically whenever a new object is created from a class. It is commonly used to assign values such as names, prices, status flags, or configuration settings. Instance methods are shared by all objects of that class, which avoids duplicating the same function for every object.

JavaScript classes support inheritance, which means one class can reuse the behavior of another class. A child class uses the extends keyword, and when it has its own constructor, it should call the parent constructor using super() before using this.

Sometimes a method belongs to the class itself rather than to individual objects. In that case, we use the static keyword. Static methods are helpful for utility functions, validation helpers, or factory methods that create instances in a special way.

Getters and setters let us control how values are read or updated. They are useful when you want to validate input or derive a formatted value without exposing all internal details directly.

Javascript Classes And Objects Worked Example

Javascript Classes And Objects Worked Example
class Song {
	constructor(name, artist) {
		this.name = name;
		this.artist = artist;
	}

	play() {
		console.log(this.name + " by " + this.artist + " is playing.");
	}
}

const mySong = new Song("Skyline", "Anaya");
mySong.play();

Javascript Classes And Objects Worked Example 2

Javascript Classes And Objects Worked Example 2
class User {
	constructor(name, email) {
		this.name = name;
		this.email = email;
	}

	introduce() {
		return "Hi, I am " + this.name;
	}
}

const user1 = new User("Riya", "riya@example.com");
console.log(user1.introduce());

Javascript Classes And Objects Worked Example 3

Javascript Classes And Objects Worked Example 3
class Course {
	constructor(title) {
		this.title = title;
	}

	getDetails() {
		return "Course: " + this.title;
	}
}

class PaidCourse extends Course {
	constructor(title, price) {
		super(title);
		this.price = price;
	}

	getPriceTag() {
		return "Price: Rs. " + this.price;
	}
}

const jsCourse = new PaidCourse("JavaScript Mastery", 999);
console.log(jsCourse.getDetails());
console.log(jsCourse.getPriceTag());

Javascript Classes And Objects Worked Example 4

Javascript Classes And Objects Worked Example 4
class Temperature {
	static toFahrenheit(celsius) {
		return (celsius * 9) / 5 + 32;
	}
}

console.log(Temperature.toFahrenheit(25)); // 77

Javascript Classes And Objects Worked Example 5

Javascript Classes And Objects Worked Example 5
class Product {
	constructor(name, price) {
		this.name = name;
		this._price = price;
	}

	get price() {
		return "Rs. " + this._price;
	}

	set price(value) {
		if (value > 0) {
			this._price = value;
		}
	}
}

const pen = new Product("Pen", 20);
pen.price = 25;
console.log(pen.price);

Objects in JavaScript

An object is a collection of key-value pairs. It is one of the most important building blocks in JavaScript because it allows us to model real-world entities such as users, products, courses, or settings. Each property describes some data, and methods describe behavior.

Objects can be created using an object literal, which is the most common and readable approach, or by using the new Object() constructor. In modern JavaScript, object literals are preferred for most cases.

Object properties can be accessed using dot notation or bracket notation. Dot notation is simple and readable, while bracket notation is useful when the property name is stored in a variable or contains spaces or special characters.

Objects can contain other objects and arrays. This is how JavaScript stores structured data such as user profiles, API responses, shopping carts, and configuration objects. Methods can also use this to refer to values within the same object.

JavaScript provides helper methods like Object.keys(), Object.values(), and Object.entries() to inspect object data. These are especially useful when we want to loop through all properties or convert object data into a format that is easier to work with.

An object is a single instance containing data and behavior. A class is a blueprint used to create many similar objects. If you only need one standalone structure, an object literal is often enough. If you need multiple similar entities with shared behavior, a class is usually the better choice.

Javascript Classes And Objects Worked Example 6

Javascript Classes And Objects Worked Example 6
const student = {
	name: "Aman",
	course: "JavaScript",
	isEnrolled: true,
	greet() {
		console.log("Welcome, " + this.name);
	}
};

student.greet();

Javascript Classes And Objects Worked Example 7

Javascript Classes And Objects Worked Example 7
const user = {
	name: "Neha",
	age: 24
};

console.log(user.name);      // Neha
console.log(user["age"]);    // 24

user.city = "Delhi";
user.age = 25;

console.log(user);

Javascript Classes And Objects Worked Example 8

Javascript Classes And Objects Worked Example 8
const profile = {
	name: "Rohit",
	skills: ["HTML", "CSS", "JavaScript"],
	address: {
		city: "Pune",
		country: "India"
	},
	introduce() {
		return this.name + " lives in " + this.address.city;
	}
};

console.log(profile.introduce());

Javascript Classes And Objects Worked Example 9

Javascript Classes And Objects Worked Example 9
const settings = {
	theme: "light",
	language: "en",
	notifications: true
};

console.log(Object.keys(settings));   // ["theme", "language", "notifications"]
console.log(Object.values(settings)); // ["light", "en", true]
console.log(Object.entries(settings));

Class and Prototype Model

JavaScript classes are syntax over constructor and prototype mechanisms with additional semantics. Instance methods are stored on the class prototype and shared by instances, while each instance owns its data fields. Class declarations are lexical, use temporal dead zone behavior, and execute in strict mode.

Calling a class without `new` throws. Construction creates an instance linked to the prototype and runs field initialization and the constructor according to base or derived class rules. A constructor should establish a valid synchronous instance and avoid returning unrelated objects.

Methods use dynamic `this` based on the call site. Extracting a method loses its instance receiver unless it is bound or wrapped. Public field arrows capture the instance but create one function per instance, so use them where callback identity justifies that cost.

Private names beginning with `#` are enforced by the language and are not ordinary string properties. They can be accessed only where declared and require a correctly branded instance. Privacy is different from immutability and does not validate data assigned to the field.

  • Understand shared prototype methods and per-instance fields.
  • Construct classes with new under strict semantics.
  • Preserve instance receivers when passing methods.
  • Treat private fields as enforced access boundaries, not validation.

Fields, Accessors, and Static State

Instance field initializers run for each new instance. In a base class they run before the constructor body; in a derived class they run after `super()` returns. Initialization order matters when a field reads another field or calls an overridable method, so keep initializers simple and avoid virtual dispatch during construction.

Getters and setters look like property access but execute functions. Keep them fast, predictable, and free of surprising network or state transitions. A setter assigning the same accessor property calls itself recursively; write to a distinct backing field or private field.

Static fields, methods, and initialization blocks belong to the class, not instances. In static methods, `this` is the class used for the call and may be a subclass. Avoid mutable static state for request, tenant, or user data because it is shared across all instances in that realm.

Property descriptors, enumerability, and serialization differ among fields, prototype methods, accessors, and private state. Define an explicit serialization method or data transfer object rather than assuming JSON.stringify captures a complete valid instance.

  • Keep field initialization order and side effects visible.
  • Use distinct backing storage for accessors.
  • Reserve static mutable state for truly shared data.
  • Serialize through an explicit public data contract.

Inheritance and Composition

`extends` links the subclass constructor and prototype chains. A derived constructor must call `super()` before using `this` or completing with the derived instance. Method `super.name()` begins lookup from the parent prototype while retaining the current receiver.

Overridden methods should preserve the behavioral contract callers expect. A subtype that narrows valid inputs, changes sync to async unexpectedly, or violates state invariants creates fragile polymorphism. Test base behavior against each supported subtype.

Deep inheritance couples construction order, protected assumptions, lifecycle, and override behavior. Prefer composition when capabilities can be supplied as collaborating objects or functions. A class can own a storage adapter, clock, validator, or transport without inheriting from each of them.

Mixins and decorators can copy or wrap methods, but they need explicit conflict, receiver, metadata, and initialization rules. Do not modify built-in prototypes or unrelated classes globally. Local composition is easier to trace and remove.

  • Call super before derived-instance access.
  • Preserve behavioral contracts across overrides.
  • Prefer composition for independent capabilities.
  • Keep mixin and wrapper effects local and explicit.

Class Design and Testing

Use a class when many instances share behavior and must preserve meaningful invariants across operations. Use a plain object for simple records, a factory for fallible or asynchronous creation, and functions for stateless transformations. Syntax preference alone is not an architecture.

Inject network, storage, time, randomness, and host APIs through constructor or factory dependencies rather than importing mutable singletons everywhere. Validate constructor inputs and keep required state valid from the moment the instance becomes observable.

Test construction, invalid input, public methods, detached-method behavior where exposed, private-state effects through public outcomes, subclass contracts, serialization, and cleanup. Avoid tests that reach through implementation details and make safe refactoring impossible.

Profile before converting objects to classes or adding private fields for performance. Engine optimizations depend on stable object shapes and real usage, but readability and correctness dominate most application models. Keep field initialization consistent and avoid adding arbitrary properties at unrelated lifecycle stages.

  • Choose classes for shared behavior and durable invariants.
  • Inject external capabilities at construction boundaries.
  • Test public behavior, subclass contracts, and cleanup.
  • Keep object shapes and initialization predictable.

Resource Ownership

Instances that open listeners, subscriptions, streams, timers, workers, or external handles need an explicit lifetime. Provide an idempotent close or dispose operation, reject use after disposal where necessary, and make the owner responsible for calling it. Garbage collection does not guarantee timely release of external resources.

Construction failure must clean up resources acquired before the failure. For multi-step asynchronous setup, use a factory that can unwind partial work before rejecting. Tests should create, use, close, close again, and force setup failure at each owned resource boundary.

  • Expose explicit cleanup for external resources.
  • Make cleanup idempotent and ownership clear.
  • Unwind partial asynchronous construction.
  • Test failure at every acquisition boundary.
Before you move on

Classes Objects in JavaScript ES6 OOP Mastery Check

4 checks
  • Separate shared prototype methods from per-instance fields.
  • Call super before using a derived instance.
  • Keep accessors and constructors predictable and synchronous.
  • Test public invariants, subclass behavior, serialization, and cleanup.
Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.