Classes & Inheritance (ES6+)
Prototype-এর উপর সিনট্যাক্স sugar — কিন্তু পরিষ্কার
1. Class Basics
basics.js
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hi, I'm ${this.name}`;
}
}
const p = new Person("Arif", 22);
console.log(p.greet());
// Proof: still prototypes underneath
console.log(typeof Person); // "function"
console.log(Object.getPrototypeOf(p) === Person.prototype);
ES6
class আসলে prototype-এর উপর সিনট্যাক্স sugar — কিন্তু সিনট্যাক্স অনেক পরিষ্কার এবং পড়তে সহজ।2. Static Methods & Class Fields
static.js
class Vector {
// Public class field
name = "vec";
constructor(x, y) {
this.x = x;
this.y = y;
}
length() { return Math.hypot(this.x, this.y); }
// Static — called on the class itself
static zero() { return new Vector(0, 0); }
static dim = 2;
}
const v = new Vector(3, 4);
console.log(v.length(), v.name);
console.log(Vector.zero(), Vector.dim);
3. Inheritance — extends & super
extends.js
class Animal {
constructor(species) { this.species = species; }
describe() { return `I am a ${this.species}`; }
}
class Dog extends Animal {
constructor(name) {
super("dog"); // must run before this
this.name = name;
}
describe() {
return super.describe() + ` named ${this.name}`;
}
bark() { return "Woof!"; }
}
const d = new Dog("Rex");
console.log(d.describe(), d.bark());
console.log(d instanceof Animal); // true
4. Getters & Setters
getset.js
class Temperature {
constructor(c) { this.c = c; }
get f() { return this.c * 9 / 5 + 32; }
set f(v) { this.c = (v - 32) * 5 / 9; }
}
const t = new Temperature(20);
console.log(t.f); // 68
t.f = 100;
console.log(t.c); // 37.7…
5. Private # Fields
private.js
class Account {
#balance = 0;
deposit(n) { this.#balance += n; }
withdraw(n) {
if (n > this.#balance) throw new Error("insufficient");
this.#balance -= n;
}
get balance() { return this.#balance; }
}
const a = new Account();
a.deposit(100);
console.log(a.balance); // 100
try { console.log(a.#balance); } // SyntaxError outside class
catch (e) {}
Composition > Inheritance
Don't reach for
extends by default. Most production code is better served by composition — small classes that hold each other as fields — rather than tall inheritance trees.
6. Class Hoisting (Or Not)
hoist.js
try {
new A();
} catch (e) {
console.log("err:", e.message);
}
class A {} // classes are NOT hoisted (TDZ like let)
new A();
console.log("ok");
7. Glossary (শব্দকোষ)
| Term | Meaning | বাংলায় |
|---|---|---|
class | ES6 syntactic sugar over prototypes for OOP. | Prototype-এর উপর ES6 syntax sugar। |
| Constructor | Special method run on new ClassName(). | new ClassName()-এ যে method চলে। |
| Static | Method/field on the class itself, not on instances. | Instance-এ নয়, class-এ থাকা method/field। |
extends | Declares a subclass that inherits from a parent. | Parent class থেকে subclass inherit করা। |
super | Calls the parent's constructor or methods. | Parent-এর constructor বা method call করে। |
| Getter / Setter | Computed property accessors via get/set. | get/set দিয়ে computed property। |
Private field # | Field accessible only inside its own class. | শুধু নিজের class-এর ভেতরে accessible। |
| Composition | Reuse via "has-a" — one class holds another as a field. | "Has-a" pattern — এক class অন্যকে field হিসেবে রাখে। |
মনে রাখুন:
class আসলে prototype-এর উপর syntax sugar — typeof Class === "function"। Class declaration let/const-এর মতো hoisted নয় (TDZ আছে)। Subclass-এ this ব্যবহারের আগে super() call করতেই হবে। Inheritance থেকে composition বেশিরভাগ সময় ভালো — tall hierarchy এড়িয়ে চলুন।
8. Practice Problems
- Write a
Rectangleclass with width, height and anarea()method.✨ Show Answer
a1.jsclass Rectangle { constructor(w, h) { this.w = w; this.h = h; } area() { return this.w * this.h; } } console.log(new Rectangle(5, 3).area()); - Add a static
square(side)factory method.✨ Show Answer
a2.jsclass Rectangle { constructor(w, h) { this.w = w; this.h = h; } area() { return this.w * this.h; } static square(s) { return new Rectangle(s, s); } } console.log(Rectangle.square(5).area()); - Make
CubeextendRectangle: add depth and override area to return surface area.✨ Show Answer
a3.jsclass Rectangle { constructor(w, h) { this.w = w; this.h = h; } area() { return this.w * this.h; } } class Cube extends Rectangle { constructor(s) { super(s, s); this.d = s; } area() { return 6 * super.area(); } } console.log(new Cube(3).area()); // 54 - Build a
Stopwatchclass with start/elapsed methods.✨ Show Answer
a4.jsclass Stopwatch { #t0 = null; start() { this.#t0 = Date.now(); } elapsed() { return Date.now() - this.#t0; } } const sw = new Stopwatch(); sw.start(); for (let i = 0; i < 1e6; i++); console.log("ms:", sw.elapsed()); - Show that calling
thisbeforesuper()in a derived constructor errors.✨ Show Answer
a5.jsclass A {} try { class B extends A { constructor() { this.x = 1; super(); } } new B(); } catch (e) { console.log("err:", e.message); } - Build a
Queuewithenqueue,dequeue, and asizegetter.✨ Show Answer
a6.jsclass Queue { #items = []; enqueue(x) { this.#items.push(x); } dequeue() { return this.#items.shift(); } get size() { return this.#items.length; } } const q = new Queue(); q.enqueue("a"); q.enqueue("b"); console.log(q.size, q.dequeue(), q.size); - Define a getter
fullNameon aPersonclass.✨ Show Answer
a7.jsclass Person { constructor(f, l) { this.f = f; this.l = l; } get fullName() { return `${this.f} ${this.l}`; } } console.log(new Person("Arif", "Hossain").fullName); - Use static method
fromJSONto build an instance from a string.✨ Show Answer
a8.jsclass User { constructor(name, age) { this.name = name; this.age = age; } static fromJSON(s) { const { name, age } = JSON.parse(s); return new User(name, age); } } console.log(User.fromJSON('{"name":"Arif","age":22}')); - Inherit and override
toStringfor aMoneyclass.✨ Show Answer
a9.jsclass Money { constructor(n) { this.n = n; } toString() { return `৳${this.n}`; } } console.log(`Total: ${new Money(99)}`); - Build a
Loggerhierarchy (Logger → DebugLogger).✨ Show Answer
a10.jsclass Logger { log(m) { console.log("[INFO]", m); } } class DebugLogger extends Logger { log(m) { console.log("[DEBUG]", m); } } new DebugLogger().log("hi"); - Why is composition often preferred over inheritance?
✨ Show Answer
Answer: Inheritance creates rigid trees: a change in the base ripples through every descendant; behaviours are coupled to the hierarchy. Composition gives the same reuse with looser bonds: a class holds a collaborator as a field and forwards calls, so each piece can be changed independently. Modern frameworks (React hooks, dependency injection) are largely composition-first.
- Use a private field to enforce a non-negative balance.
✨ Show Answer
a12.jsclass Wallet { #b = 0; deposit(n) { if (n < 0) throw new Error("negative"); this.#b += n; } get balance() { return this.#b; } } const w = new Wallet(); w.deposit(100); console.log(w.balance); try { w.deposit(-10); } catch (e) { console.log(e.message); } - Test that a class instance is also an instance of
Object.✨ Show Answer
a13.jsclass A {} const x = new A(); console.log(x instanceof A, x instanceof Object); - Class expression: assign a class to a variable and instantiate it.
✨ Show Answer
a14.jsconst Box = class { constructor(v) { this.v = v; } }; console.log(new Box(42).v); - Use
extendsto add a method to all instances ofArray… by subclassing.✨ Show Answer
a15.jsclass SafeArr extends Array { first() { return this[0]; } last() { return this.at(-1); } } const a = SafeArr.from([10, 20, 30]); console.log(a.first(), a.last()); - Show that
typeof Class === "function".✨ Show Answer
a16.jsclass A {} console.log(typeof A); // "function"
Summary — Module 17
ES6 class is sweet syntax over the same prototype chain you saw last lecture. Classes give you constructor, methods, static members, getters/setters, private # fields, and clean extends/super. Classes are not hoisted. Favour composition over deep inheritance.
Class হলো prototype-এর উপর syntax sugar — কিন্তু পরিষ্কার। Inheritance ব্যবহার করতে পারেন, কিন্তু composition বেশিরভাগ সময় ভালো।