Object Oriented JavaScript (OOP) Deep Dive

"The Architecture of Objects"

জাভাস্ক্রিপ্ট একটি অদ্ভুত ল্যাঙ্গুয়েজ। জাভা বা সি-শার্পে OOP কাজ করে Class এর ওপর ভিত্তি করে। কিন্তু জাভাস্ক্রিপ্টে OOP কাজ করে Prototype এর ওপর ভিত্তি করে।

ES6 এ আমরা class কিওয়ার্ড ব্যবহার করি ঠিকই, কিন্তু ব্যাকগ্রাউন্ডে বা ইঞ্জিনের ভেতরে সেটা আসলে প্রোটোটাইপ দিয়েই কাজ করে। একে বলা হয় "Syntactic Sugar" (ভেতরে তিতা ওষুধ, বাইরে মিষ্টির প্রলেপ)।

এই অধ্যায়ে আমরা অবজেক্টের একদম হাড়হাপ্পা (Skeleton) বা DNA দেখব।

⭐ ১. this কিওয়ার্ডের ভেলকিবাজি (The Most Confusing Part)

সিনিয়র ডেভেলপার হওয়ার প্রথম শর্ত হলো this কে বশ করা। মনে রাখবে: this এর মান নির্ভর করে ফাংশনটি কোথায় লেখা আছে তার ওপর না, বরং ফাংশনটি কে কল করছে তার ওপর।

রুল ১: অবজেক্ট মেথড (Object Method)

যখন কোনো অবজেক্টের মেথড হিসেবে কল হয়, this মানে সেই অবজেক্ট।

const user = {
    name: "Shagor",
    greet() {
        console.log(this.name); // 'this' হলো user অবজেক্ট
    }
};
user.greet(); // Output: Shagor

রুল ২: গ্লোবাল বা সাধারণ ফাংশন (Global Function)

সাধারণভাবে কল করলে this হয় window (ব্রাউজারে) বা global (নোডে)। তবে strict mode এ এটা undefined হয়।

function show() {
    console.log(this);
}
show(); // Window / undefined

রুল ৩: Arrow Function (The Exception 🚨)

অ্যারো ফাংশনের নিজস্ব কোনো this নেই। সে তার বাবার (Lexical Scope) this ধার করে।

const user = {
    name: "Rahim",
    // ❌ ভুল উপায়: Arrow function এর নিজস্ব this নেই
    sayHi: () => {
        console.log(this.name); 
    }
};
user.sayHi(); // undefined

Decision:

অবজেক্টের মেথড লেখার সময় সবসময় নরমাল ফাংশন ব্যবহার করবে, অ্যারো ফাংশন নয়।

⭐ ২. Prototypes: জাভাস্ক্রিপ্টের DNA 🧬

জাভাস্ক্রিপ্টে ইনহেরিটেন্স বা উত্তরাধিকার ক্লাস দিয়ে হয় না, হয় চেইন (Chain) দিয়ে। ধরো তুমি user.toString() কল করলে। তোমার user অবজেক্টে তো toString নেই, তাহলে কাজ করলো কীভাবে?

  • JS প্রথমে user এর কাছে খোঁজে
  • না পেলে তার বাবার কাছে (User.prototype) যায়
  • সেখানেও না পেলে তার দাদার কাছে (Object.prototype) যায়
  • সেখানে toString আছে! তাই কাজ করে

একে বলা হয় Prototype Chain

const human = {
    eat() { console.log("Eating..."); }
};

const developer = Object.create(human); // human কে বাবা বানাও
developer.code = function() { console.log("Coding..."); };

developer.code(); // Coding... (নিজের কাছে আছে)
developer.eat();  // Eating... (বাবার কাছ থেকে পেয়েছে - Prototype)

⭐ ৩. Classes: The Modern Blueprint (ES6)

এখন আমরা প্রোটোটাইপ ম্যানুয়ালি লিখি না, class কিওয়ার্ড ব্যবহার করি। এটি দেখতে ক্লিন এবং অন্যান্য ল্যাঙ্গুয়েজের মতো।

class User {
    // 1. Constructor: অবজেক্ট তৈরির সময় প্রথমে এটা কল হয়
    constructor(name, email) {
        this.name = name;
        this.email = email;
    }

    // 2. Instance Method: সব অবজেক্ট এটা পাবে
    login() {
        console.log(`${this.name} just logged in.`);
    }

    // 3. Static Method: অবজেক্ট ছাড়াই ক্লাস দিয়ে কল করা যায়
    static compare(user1, user2) {
        return user1.name === user2.name;
    }
}

const u1 = new User("Shagor", "s@test.com");
u1.login(); // "Shagor just logged in."

// User.login() ❌ কাজ করবে না
User.compare(u1, u1); // ✅ কাজ করবে (Static)

⭐ ৪. Inheritance: বাপ কা বেটা (extends & super)

এক ক্লাসের বৈশিষ্ট্য অন্য ক্লাসে পাওয়ার নামই ইনহেরিটেন্স।

// Parent
class Animal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name} makes a noise.`);
    }
}

// Child
class Dog extends Animal {
    constructor(name, breed) {
        super(name); // 🚨 মাস্ট! বাবার কনস্ট্রাক্টর আগে কল করতে হবে
        this.breed = breed;
    }

    // Overriding (বাবার মেথড বদলে ফেলা - Polymorphism)
    speak() {
        console.log(`${this.name} barks! Woof Woof!`);
    }
}

const dog = new Dog("Tommy", "Shepherd");
dog.speak(); // "Tommy barks! Woof Woof!"

super(name) মানে হলো: "আগে বাবার name সেট করার লজিকটা চালিয়ে আসো, তারপর আমি আমার breed সেট করব।"

⭐ ৫. Encapsulation: Private Fields (#) 🔒

আগে আমরা প্রাইভেট প্রপার্টি বোঝাতে _variable ব্যবহার করতাম (যা আসলে প্রাইভেট ছিল না, শুধু কনভেনশন ছিল)। ES2022 তে সত্যিকারের প্রাইভেট ফিল্ড এসেছে # দিয়ে।

class BankAccount {
    #balance = 0; // প্রাইভেট প্রপার্টি

    constructor(initial) {
        this.#balance = initial;
    }

    deposit(amount) {
        this.#balance += amount;
        console.log(`Deposited: ${amount}`);
    }

    getBalance() {
        return this.#balance; // ক্লাসের ভেতর থেকে এক্সেস করা যাবে
    }
}

const myAccount = new BankAccount(100);
myAccount.deposit(50);

// console.log(myAccount.#balance); // ❌ Error! (Private field accessed outside class)
console.log(myAccount.getBalance()); // ✅ 150

⭐ ৬. Polymorphism: বহুরূপী আচরণ

একই মেথড, কিন্তু একেক ক্লাসে একেক রকম কাজ করে।

class Shape {
    area() { return 0; }
}

class Circle extends Shape {
    constructor(r) { super(); this.r = r; }
    area() { return Math.PI * this.r ** 2; } // গোলকের এরিয়া
}

class Square extends Shape {
    constructor(a) { super(); this.a = a; }
    area() { return this.a ** 2; } // বর্গের এরিয়া
}

const shapes = [new Circle(10), new Square(10)];
shapes.forEach(shape => console.log(shape.area())); // লুপ চালিয়ে ভিন্ন ভিন্ন রেজাল্ট

⭐ ৭. The this Losing Context Problem (Senior Interview Favourite)

রিয়েক্ট বা ভ্যানিলা জেএস—এই ভুলটা সবাই করে।

class Timer {
    constructor() {
        this.seconds = 0;
    }

    start() {
        // ❌ ভুল: সাধারণ ফাংশন 'this' হারিয়ে ফেলে
        setInterval(function() {
            this.seconds++; 
            console.log(this.seconds); // NaN বা Error দেবে
        }, 1000);
    }
    
    startFixed() {
        // ✅ সঠিক: Arrow Function 'this' ধরে রাখে
        setInterval(() => {
            this.seconds++;
            console.log(this.seconds); // 1, 2, 3...
        }, 1000);
    }
}

🧠 ৮. Senior Level Interview Q&A

Q1: জাভাস্ক্রিপ্টে কি Multiple Inheritance সাপোর্ট করে?

উত্তর: না। একটি ক্লাস কেবল একটি ক্লাসকেই extends করতে পারে। তবে Mixins ব্যবহার করে আমরা মাল্টিপল ইনহেরিটেন্সের মতো আচরণ তৈরি করতে পারি।

Q2: super কিওয়ার্ডটি কখন ব্যবহার করতেই হয়?

উত্তর: চাইল্ড ক্লাসে যদি constructor ব্যবহার করো, তবে অবশ্যই সবার আগে super() কল করতে হবে। নাহলে this তৈরি হবে না এবং এরর দেবে।

Q3: __proto__ এবং prototype এর পার্থক্য কী?

উত্তর: prototype থাকে ফাংশন বা ক্লাসের কাছে (Blueprint)। আর __proto__ থাকে সেই ক্লাস থেকে তৈরি হওয়া অবজেক্টের কাছে (Link)। u1.__proto__ === User.prototype।

Q4: Arrow Function কেন ক্লাসের মেথড হিসেবে ব্যবহার করা উচিত নয়?

উত্তর: টেকনিক্যালি করা যায়, কিন্তু এতে মেমোরি বেশি খরচ হয়। কারণ অ্যারো ফাংশন প্রোটোটাইপে যায় না, প্রতিটা অবজেক্টের জন্য নতুন করে কপি তৈরি হয়।

📊 OOP Concepts Comparison

Concept JavaScript Way Other Languages (Java/C#)
Inheritance Prototype Chain Class-based
Encapsulation # (Private Fields - ES2022) private keyword
Polymorphism Method Overriding Method Overloading + Overriding
Abstraction Not fully supported Abstract classes, Interfaces

🚀 অধ্যায় ১৩ সারাংশ (Checklist)

আমরা শিখলাম:

  • Core: জাভাস্ক্রিপ্ট ক্লাস ভিত্তিক নয়, প্রোটোটাইপ ভিত্তিক
  • Creation: class সিনট্যাক্স দিয়ে ব্লুপ্রিন্ট তৈরি করা সহজ
  • Inheritance: extends দিয়ে চাইল্ড ক্লাস এবং super দিয়ে প্যারেন্ট কল
  • Privacy: # দিয়ে সত্যিকারের প্রাইভেট ভেরিয়েবল তৈরি
  • Trap: setTimeout বা কলব্যাকে this হারিয়ে গেলে Arrow Function ব্যবহার করা

Next Step: আমরা OOP শিখে ফেলেছি। কিন্তু এই কোডগুলো যখন বড় হয়ে যাবে, তখন সব এক ফাইলে রাখা অসম্ভব। আমাদের কোড ভাঙতে হবে। পরের অধ্যায়: "Modules & Bundlers (Import/Export)"।

🔒 কপিরাইট সুরক্ষিত কন্টেন্ট 🔒

কপি, স্ক্রিনশট, প্রিন্ট করা সম্পূর্ণ নিষিদ্ধ।