৭.১ জাভাস্ক্রিপ্টে অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং কি?

OOP বা অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং হল এক ধরনের কম্পিউটার প্রোগ্রামিং ধারণা যা অবজেক্ট কে ভিত্তি করে গঠিত। একজন ভাল সফটওয়্যার ইঞ্জিনিয়ার হতে চাইলে অবশ্যই অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং সম্পর্কে খুব ভাল ধারণা থাকতে হবে। আমরা প্রতিনিয়ত যেই সফটওয়্যার গুলো ইউজ করি অথবা নাম শুনেছি তা অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এর ধারণার উপর ভিত্তি করেই তৈরি করা হয়েছে। বৃহৎ আকারের কোনো সফটওয়্যার বানাতে গেলে আমাদের লিখা কোডগুলো যেন আরেকজনের কাছে বোধগম্য হয়, যাতে কোনো ঝামেলা ছাড়াই আরেকজন সেটা নিয়ে কাজ করতে পারে এবং ছোটো ছোটো ভাগে ভাগ করা যায় সেই সুবিধা গুলো থাকা দরকার। তাছাড়া আমাদের কোডের সাথে এক্সট্রা বৈশিষ্ট্যও যাতে এড করা যায়। এসব তাড়না ঠেকেই মূলত OOP Concepts গুলো তৈরি।

অবজেক্ট কি?

অনেক বকবক করে ফেললাম। এখন আমাদের মনে প্রশ্ন জাগতে পারে যে, অবজেক্ট জিনিস টা তাহলে কি? আসলে বস্তুগত ভাবে আমাদের চারপাশে আমরা যা দেখতে পাই অথবা অনুভব করতে পারি তাই অবজেক্ট। ধরা যাক, আমরা এখন কম্পিউটার দিয়ে এই ব্লগটা পড়তেছি, তাহলে আমাদের কম্পিউটারই একটা অবজেক্ট। আবার কম্পিউটারের প্রত্যেকটা উপাদানও একেকটা অবজেক্ট। যেমনঃ মাউস, কীবোর্ড, মনিটর ইত্যাদি। কম্পিউটার সায়েন্সের ভাষায় অবজেক্ট একটি ভ্যারিয়েবল, ফাংশন, ডাটা স্ট্রাকচার যেকোনো কিছুই হতে পারে। অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং-এ অবজেক্ট সাধারণত ভ্যারিয়েবল, ফাংশন কিংবা ডাটা স্ট্রাকচারের সমন্বয়ে হয়ে থাকে। অবজেক্ট জাভাস্ক্রিপ্টের প্রায় সব স্থানেই বিদ্যমান। তাই, জাভাস্ক্রিপ্ট নিয়ে কাজ করতে হলে অবজেক্ট সম্পর্কে ধারণা থাকা অনেক বেশি জরুরী।

আপনারা অন্যান্য ল্যাংগুয়েজে অবজেক্ট সম্পর্কে জেনে থাকতে পারেন। কিন্তু জাভাস্ক্রিপ্টে অবজেক্ট একটু আলাদা, অবজেক্ট তৈরি করার জন্য এখানে ক্লাস বানাতে হয়না আগে। নিচের উদাহরণটি খেয়াল করিঃ

// অবজেক্ট
const student = {
name: 'Mehedi',
class: 12
};

 

উপরে student নামে একটি অবজেক্ট তৈরি করা হয়েছে যা স্ট্রিং আর নাম্বার স্টোর করে।
জাভাস্ক্রিপ্টে অবজেক্ট key:value pair এ থাকে, যার প্রত্যেকটা সদস্যকে কমা (,) দিয়ে আলাদা করা হয়। নিচের উদাহরণটি খেয়াল করিঃ

const object_name = {
key1: value1,
key2: value2
}

 

৭.৩ অবজেক্ট প্রপার্টি এবং মেথড:

 

অবজেক্ট প্রপার্টি:

অবজেক্টের প্রত্যেকটা key:value পেয়ারগুলোকে অবজেক্ট properties বলা হয়। যেমন উপরের student অবজেক্টে name: ’Mehedi’ আর class: 12 অবজেক্টের properties।

অবজেক্টের properties গুলোকে আমরা দুইভাবে এক্সেস করতে পারি। সেগুলো হচ্ছেঃ

১। ডট নোটেশন ব্যবহার করে

ডট নোটেশন দিয়ে অবজেক্ট এক্সেস করার সিনট্যাক্স এমন হয়ঃ

objectName.key

 

যেমন, উপরের student অবজেক্ট কে আমরা এভাবে এক্সেস করতে পারি।

// অবজেক্ট
const student = {
name: 'Mehedi',
class: 12
};

// ডট নোটেশন দিয়ে অবজেক্ট এক্সেস করা
console.log(student.name) // আউটপুটঃ Mehedi

 

২। ব্র্যাকেট নোটেশন ব্যবহার করে

ব্র্যাকেট নোটেশন দিয়ে অবজেক্ট এক্সেস করার সিনট্যাক্স এমন হয়ঃ

objectName["propertyName"]

 

যেমন, উপরের student অবজেক্ট কে আমরা এভাবে এক্সেস করতে পারিঃ

// অবজেক্ট
const student = {
name: 'Mehedi',
class: 12
};

// ব্র্যাকেট নোটেশন দিয়ে অবজেক্ট এক্সেস করা
console.log(student["name"]) // আউটপুটঃ Mehedi

 

এখন আমরা চাইলে নেস্টেড অবজেক্ট মানে একটা অবজেক্টের মধ্যে আরও অবজেক্ট ডিফাইন করতে পারি।

// অবজেক্ট
const student = {
   name: 'Mehedi',
   class: 12,
   marks: {
     physics: 80,
     biology: 55
   }
};

 

অবজেক্ট মেথড :

জাভাস্ক্রিপ্টে অবজেক্টের মধ্যে ফাংশনও থাকতে পারে। যেমনঃ

const student = {
   name: 'Mehedi',
   class: 12,
   greet: function (){
     console.log("Hello!")
   }
};

 

এটিও অবজেক্টের একটি প্রোপার্টি। এই ধরণের প্রোপার্টিকে মেথড বলা হয়। সোজা কোথায়, অবজেক্টের মধ্যের ফাংশনকেই মেথড বলা হয়।

 

আমরা নিচের মতো করে অবজেক্টের মেথড এক্সেস করতে পারিঃ

const student = {
   name: 'Mehedi',
   class: 12,
   greet: function (){
     console.log("Hello!")
   }
};

student.greet(); // আউটপুটঃ Hello!

 

আশা করি আমাদের অবজেক্ট সম্পর্কে ধারণা পরিষ্কার হয়েছে। অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এর কিছু বৈশিষ্ট্য আছে, যেইগুলা থাকলে আমরা একটা ল্যাংগুয়েজকেঅবজেক্ট ওরিয়েন্টেড ল্যাংগুয়েজ বলতে পারি। আমরা নিচের মত করে অবজেক্ট মেথড ব্যবহার করতে পারি।

Object Oriented Programming System

আমরা ইতিমধ্যে অবজেক্ট নিয়ে আলোচনা করেছি। এখন আমরা বাকি জিনিসগুলো নিয়ে আলোচনা করব।

  • OOP Examples
  • OOP Practices
  • OOP Interview Questions

 

৭.৪ Class (ক্লাস):

ক্লাস হলো এমন একটি টেম্পলেট যা ভ্যারিয়েবল এবং ফাংশনের সমন্বয়ে তৈরি। শুনতে তো অবজেক্ট এর মতোই হয়ে গেল তাইনা? আরেকটু ভালোভাবে ভাবে বলতে গেলে, ক্লাস হলো একধরণের blueprint যা থেকে সুনির্দিষ্ট অবজেক্ট তৈরি করা হয়। ক্লাসের মধ্যেও Attributes এবং Function থাকে যাদেরকে Method বলা হয়। নিচের কোডটি খেয়াল করিঃ

class Car {
    constructor(color, brand, model){
        this.color = color;
        this.brand = brand;
        this.model = model;
    }
    repaint(){
        this.color = "Red";
    }
}

const myCar = new Car("Black", "Doge", "Charger");
const helensCar = new Car("Blue", "Nissan", "Ultima");

 

আমরা একটা Car নামে ক্লাস তৈরি করেছি। তার মধ্যে properties হিসেবে color, brand এবং model দিয়েছি। এবং তার মধ্যে repaint নামে একটি মেথড দিলাম যা গাড়ির রং পরিবর্তন করে। তারপর এই ক্লাস থেকে আমরা দুইটি ‘Car’ টাইপের অবজেক্ট myCar এবং helensCar তৈরি করেছি।এখন আমরা চাইলে এই ক্লাস থেকে হাজারটা অবজেক্টও তৈরি করতে পারব এবং প্রত্যেকটা অবজেক্টেরই ইউনিক প্রোপার্টি থাকবে।

ক্লাসের কোড তো দেখলাম। এখন আমাদের মনে প্রশ্ন জাগতে পারে যে Car ক্লাসের মধ্যে constructor জিনিসটা আবার কি? constructor একটি স্পেশাল ধরণের ফাংশন যার সাহায্যে অবজেক্ট কে ইনিশিয়ালাইজ করা যায়। আরেকটু সহজ করে বলতে গেলে, এটি এমন একধরনের ফাংশন যা নিজেকে নিজেই কল করে। আমরা যখন ‘new’ keyword ব্যবহার করে কোনো ক্লাসের অবজেক্ট তৈরি করি, তখনই সাথে সাথেই constructor ফাংশনটি কল হয় এবং অবজেক্টের মধ্যে কোন ভ্যালু সেট করে দিলে constructor এর মধ্যে সেগুলো এসাইন হয়ে যায়। ‘new’ keyword এর ব্যবহার নিয়ে আমরা পরবর্তীতে বিস্তারিত আলোচনা করব। constructor এর কাজই হচ্ছে অবজেক্ট তৈরি করা এবং অবজেক্টের কোনো প্রোপার্টি থাকলে তাদের ভ্যালু সেট করা। এটা অবজেক্ট তৈরি করার খুবই সহজ পদ্ধতি কারণ আমাদের কষ্ট করে অবজেক্ট রিটার্ন করতে হয়না। জাভাস্ক্রিপ্টে কোনো ক্লাস তৈরি করার সময় অটোম্যাটিক constructor তৈরি হয়ে যায়, কোনো প্যারামিটার ছাড়াই।

constructor(){

}

 

Inheritance (ইনহেরিটেন্স):

Inheritance এর অর্থ উত্তরাধিকার। একজন সন্তান হয়ত উত্তরাধিকার সূত্রে তার বাবা-মার সম্পত্তি অটোমেটিকালি পেয়ে যাবে, তার বাবা-মা হয়ত সেই সম্পত্তি পেয়েছিল তার দাদা-দাদিমার থেকে। সেক্ষেত্রে আমরা বলতে পারি চাইল্ড ইনহেরিটেড প্রপার্টিজ ফ্রম হিজ প্যারেন্টস। OOP তেও ইনহেরিটেন্স বলতে এইটাই বোঝায়। চাইল্ড ক্লাস তার প্যারেন্ট ক্লাসের attributes এবং behavior ইনহেরিট করে।

ইনহেরিটেন্স মূলত কোড reusability এর জন্য ব্যবহৃত হয়। ইনহেরিটেন্সের সুবিধা হল প্রোগ্রামগুলি একটি সাধারণ প্যারেন্ট ক্লাস তৈরি করতে পারে এবং তারপর প্রয়োজন অনুসারে আরও নির্দিষ্ট চাইল্ড ক্লাস তৈরি করতে পারে। এটা প্রোগ্রামিংকে সহজ করে, কারণ একটা ক্লাস একাধিকবার তৈরি করার প্রয়োজন হয় না, চাইল্ড ক্লাসগুলি এমনিতেই প্যারেন্টের প্রোপার্টির এক্সেস পেয়ে যায়। উপরের কথাগুলা যদি না বুঝে থাকেন তাহলে নিচের কোডটি খেয়াল করলে আশা করি আপনাদের ধারণা পরিষ্কার হয়ে যাবে।

class Dog {
   constructor(name, age){
     this.name = name;
     this.age = age;
   }
   bark (){
     console.log("woof!");
   }
}

class HuskyDog extends Dog {
   constructor(name, age){
     super(name, age);
   }
   play () {
     console.log(this.name+ " is playing");
   }
}

const hachi = new HuskyDog("Hachi", 2);
hachi.bark(); // Output: woof!
hachi.play(); // Output: Hachi is playing

 

এখানে Dog নামে একটা ক্লাস তৈরি করা হয়েছে, যার মধ্যে bark মেথডটি আছে। HuskyDog ক্লাসটি যখন Dog ক্লাসকে extend করে, তখন প্যারেন্ট ক্লাস Dog এর bark মেথডটি ইনহেরিট করে ফেলে। তাই আমরা যখন HuskyDog ক্লাসের একটা অবজেক্ট বা ইন্সট্যান্স তৈরি করি, তখন আমরা খুব সহজেই সব মেথডই এক্সেস করতে পারি।

প্যারেন্ট ক্লাস super ক্লাস বা base ক্লাস নামেও পরিচিত। চাইল্ড ক্লাসকে derived ক্লাস বা extended ক্লাসও বলা যেতে পারে।

Polymorphism (পলিমরফিজম):

পলিমরফিজম শব্দটির বাংলা অর্থ ভিন্নরূপ। অর্থাৎ কোন জিনিসের ভিন্ন ভিন্ন রূপকেই পলিমরফিজম বলে। এখানেও তাই। আমরা বিভিন্ন কাজের জন্য ফাংশন তৈরি করি। এমন ধরণের ফাংশন তৈরি করা লাগতে পারে যেগুলা ভিন্ন ভিন্ন কাজ করে। যেমন একই ফাংশন কিন্তু ইন্টিজার প্যারামিটার নিয়ে একরকম কাজ করে আর স্ট্রিং প্যারামিটার নিয়ে আরেকরকম কাজ করে। আবার এমনো হতে পারে যে অনেকগুলা ফাংশন মিলে একই কাজ করছে। পলিমরফিজমে ফাংশন বা মেথডকে ভিন্ন কাজে ব্যবহার করা হয় সাধারণত দুইটি নিয়মে। সেগুলো হচ্ছেঃ

১। Method Overriding
২। Method Overloading

Method Overriding (মেথড ওভাররাইডিং):

মেথড ওভাররাইডিং-এ চাইল্ড ক্লাস প্যারেন্ট ক্লাসের মেথডকে override করে। মানে চাইল্ড ক্লাস চাইলে প্যারেন্ট ক্লাসের মেথডের কাজের পরিবর্তন করতে পারে। নিচের কোডটি দেখলে আশা করি আপনাদের ধারণা পরিষ্কার হবে।

class Dog {
   constructor(name, age){
      this.name = name;
      this.age = age;
   }
   bark (){
      console.log("Dog barking");
   }
}

class HuskyDog extends Dog {
   constructor(name, age){
      super(name, age);
   }
   bark(){
      console.log("Husky dog barking")
   }
   play () {
      console.log(this.name+ " is playing");
   }
}

const hachi = new HuskyDog("Hachi", 2);
hachi.bark(); // Output: Husky dog barking
hachi.play(); // Output: Hachi is playing

 

এখানে HuskyDog ক্লাসটি প্যারেন্ট ক্লাস Dog কে ইনহেরিট করে। তার মানে প্যারেন্ট ক্লাসের bark মেথডটিও তার হয়ে যাবে। কিন্তু সে তার নিজের ক্লাসের মধ্যেই bark মেথডটি আলাদা ভাবে বানায়। যার কারণে bark মেথডটি এখানে override হয়ে যাবে। এভাবে চাইলে আমরা ইনহেরিটেড মেথড override করতে পারি।

Method Overloading (মেথড ওভারলোডিং):

মেথড অভারলোডিং হলো একই মেথড কে দিয়ে ভিন্নরকম কাজ করানো। যেমনঃ একই নামের ফাংশনের প্যারামিটার যখন দুইটা দিয়ে কল করা হবে তখন সেটি এক কাজ করবে, আবার তিনটা প্যারামিটার দিয়ে কল করা হলে আরেক কাজ করবে। নিচের কোডটি খেয়াল করিঃ

class Dog {
   constructor(name, age){
      this.name = name;
      this.age = age;
   }
   bark (){
      console.log("Dog barking");
   }
   play(){
      console.log(this.name+" is playing")
   }
   play(partner){
      console.log(this.name+" is playing with "+ partner)
   }
   play(partner1, partner2){
      console.log(this.name+" is playing with "+ partner1+ " and "+partner2)
   }
}

const hachi = new Dog("Hachi", 2);
hachi.play();                      // Output: Hachi is playing with undefined and undefined
hachi.play("Broley");              // Output: Hachi is playing with Broley and undefined
hachi.play("Broley", "Bravo");     // Output: Hachi is playing with Broley and Bravo

 

এখানে আমরা একই নামের মেথড play কে দিয়ে ভিন্ন রকমের কাজ করিয়েছি। কিন্তু আউটপুটে undefined হওয়ার কারণ হল, অন্যান্য ল্যাংগুয়েজের মতো জাভাস্ক্রিপ্ট মেথড ওভারলোডিং সাপোর্ট করে না। এইটা কি কারণে হয় বলেন দেখি! এইটা হয় hoisting এর জন্য। কারণ জাভাস্ক্রিপ্টে ফাংশন ডিক্ল্যারেশন hoisted হয়।

আমরা চাইলে একই নামের ফাংশনের এই সমস্যা দুর করতে পারি কিছু টেকনিক অবলম্বন করে। এইগুলা আমরা পরবর্তী লেখায় জানবো।

Abstraction (এবস্ট্রাকশন):

Abstraction হলো এমন একটি ধারণা, যেখানে কোনো প্রোগ্রামের অভ্যন্তরীণ বিষয়গুলো ইউজারকে না দেখিয়ে শুধুমাত্র ফাংশনালিটি দেখাবে। যেমনঃ একটা গাড়ী চালাতে হলে আপনার গাড়ীর ইঞ্জিন কিভাবে কাজ করে তার সবকিছু জানার প্রয়োজন নেই। শুধুমাত্র selected কিছু জিনিস জানা দরকার যেমন gas pedal, brake, steering wheel, blinker ইত্যাদি। গাড়ীর ভিতরের ইঞ্জিনিয়ারিং গোপন রাখা হয় ড্রাইভারের থেকে।

Abstraction in OOP

কোডের সিকিউরিটি রক্ষার্থেও abstraction খুবই গুরুত্বপূর্ণ ভূমিকা পালন করে।

Encapsulation (এনক্যাপসুলেশন):

Encapsulation শব্দটি এসেছে capsule শব্দ থেকে। প্রয়োজনীয় ইনফরমেশন একটা অবজেক্টের মধ্যে রেখে শুধুমাত্র selected ইনফরমেশন যাতে বাহির থেকে এক্সেস করতে পারে, এই ধারণাটাই মূলত এনক্যাপসুলেশন।

এনক্যাপসুলেশন এর জন্য কিছু জিনিসকে পাবলিক এবং কিছু জিনিসকে প্রাইভেট করে ডিফাইন করার প্রয়োজন হয়।

প্রাইভেটঃ মেথড এবং প্রোপার্টি শুধুমাত্র একই ক্লাসের অন্যান্য মেথড থেকে এক্সেস করা যাবে।
পাবলিকঃ মেথড এবং প্রোপার্টি ক্লাসের বাইরে থেকে এক্সেস করা যাবে।

আরেকটু ভালোভাবে বুঝতে আমরা গাড়ীর সাথে তুলনা করতে পারি। গাড়ীর blinkers হলো পাবলিক প্রোপার্টি, যা বাইরের মানুষ দেখতে পারে। অন্যদিকে গাড়ীর ইঞ্জিনের মধ্যকার জিনিসগুলি প্রাইভেট প্রোপার্টি। অন্য কেউ চাইলেই গাড়ীর ভিতরের ইঞ্জিনের কাজ দেখতে পারেনা।

encapsulation in oop

আশা করি এনক্যাপ্সুলেশনের ধারণা আমরা পেয়েছি। পরবর্তীতে আমরা আরও গভীরভাবে আলোচনা করব।

আমরা অবজেক্ট ওরিয়েন্টেড কনসেপ্টস গুলো জানলাম। আমরা প্রতিনিয়তই OOP নিয়ে কাজ করব, কাজেই এ সম্পর্কে খুব ভাল ধারণা থাকা অনেক জরুরী। আশা করি আপনাদের OOP সম্পর্কে ধারণা পরিষ্কার হয়েছে।

  • Javascript Class Examples
  • Javascript Class Practices
  • Javascript Class Interview Questions

 

৭.৫ Factory Pattern ব্যবহার করে ক্লাস তৈরি করা:

আমরা Factory Pattern সম্পর্কে জেনেছি। দেখেছি কীভাবে Factory Function ব্যবহার করতে হয়। আজ আমরা দেখব কীভাবে Factory Pattern ব্যবহার করে ক্লাস তৈরি করা যায়।

Factory Pattern সম্পর্কে আমরা জানি যে, এটি দিয়ে অবজেক্ট তৈরি করা যায় ডিরেক্টলি new কিওয়ার্ড ব্যবহার না করে। তার পরিবর্তে এইটা একটা কমন ইন্টারফেস তৈরি করে যা সাবক্লাসগুলো দিয়ে অবজেক্ট তৈরি করে। ধরা যাক, একটা cake এর ফ্যাক্টরিতে হরেক রকমের cake তৈরি করা হয়। যেমনঃ চকলেট, পাউন্ড আর বিস্কুট cake। এক্ষেত্রে আমরা কীভাবে ফ্যাক্টরি প্যাটার্ন ফলো করে কাজ করব? নিচের উদাহরণটি খেয়াল করি।

class CakeFactory {
   constructor(){
      this.createCake = function(flavor){
          let cake;
          if(flavor === "chocolate"){
             cake = new ChocolateCake();
          }
          else if(flavor === "biscuit"){
             cake = new BiscuitCake();
          }
          else if(flavor === "pound"){
             cake = new PoundCake();
          }
          return cake;
      }
   }
}

class ChocolateCake {
   constructor(){
      this.cakeFlavor = "Chocolate Cake";
      this.made = function (){
         console.log("You made "+this.cakeFlavor)
      }
   }
}

class BiscuitCake {
    constructor(){
      this.cakeFlavor = "Biscuit Cake";
      this.made = function (){
        console.log("You made "+this.cakeFlavor)
      }
   }
}

class PoundCake {
    constructor(){
      this.cakeFlavor = "Pound Cake";
      this.made = function (){
        console.log("You made "+this.cakeFlavor)
      }
   }
}

const cakeFactory = new CakeFactory();
const chocolate = cakeFactory.createCake("chocolate");
const pound = cakeFactory.createCake("pound");
const biscuit = cakeFactory.createCake("biscuit")
chocolate.made()                          // আউটপুটঃ You made Chocolate Cake
pound.made()                              // আউটপুটঃ You made Pound Cake
biscuit.made()                            // আউটপুটঃ You made Biscuit Cake

 

দেখতে অনেক বড় হলেও কোডটি সহজ। সবার উপরে আমরা CakeFactory নামে একটা ক্লাস তৈরি করেছি, যা একটি জেনেরিক টেম্পলেট হিসেবে কাজ করবে অন্যান্য সাবক্লাস দিয়ে অবজেক্ট তৈরি করার জন্য। মানে, ChocolateCake, PoundCake আর BiscuitCake ক্লাসগুলোকে দিয়ে অবজেক্ট তৈরি করে। CakeFactory ক্লাসের constructor এ একটি ফাংশন আছে createCake নামে যা প্যারামিটার হিসেবে flavor নেয়, যদি flavor chocolate হয় তাহলে ChocolateClass এর একটি অবজেক্ট তৈরি হবে, অন্যান্য flavor হলে অন্যান্য ক্লাসের অবজেক্ট তৈরি হবে।

এভাবেই আমরা Factory টেম্পলেট ব্যবহার করে একই রকমের আলাদা আলদা অবজেক্ট তৈরি করতে পারি।

  • JS Factory Pattern Examples
  • JS Factory Pattern Practices
  • JS Factory Pattern Interview Questions

৭.৬ Constructor Pattern ব্যবহার করে জাভাস্ক্রিপ্টের ক্লাস তৈরি:

আমরা constructor ফাংশন ব্যবহার করে জাভাস্ক্রিপ্টের constructor pattern সম্পর্কে জেনেছি। Constructor Function এমন একটি ফাংশন যা Object তৈরি করতে পারে। Constructor function ব্যবহার করে Object তৈরি করার প্রক্রিয়াই আসলে constructor pattern। নিচের কোডটি খেয়াল করিঃ

function CreateCircle(radius){
    this.radius = radius;
    this.draw = function () {
      console.log(`Circle radius is ${this.radius}`);
    };
}

const circle1 = new CreateCircle(5);

 

আমরা এখানে ফাংশন দিয়ে constructor pattern ইমপ্লিমেন্ট করেছি। CreateCircle Constructor Function ব্যবহার করে circle Object তৈরি করেছি। উপরের কোডে আমারা একটা নতুন Keyword ব্যবহার করেছি তা হল new নিশ্চয়ই লক্ষ্য করেছেন। আশা করি আপনারা new keywoআমারা যখন এই new Keyword টা ব্যবহার করি তখন আসলে তিনটি জিনিস ঘটে। প্রথমত, এই new Keyword একটি খালি বা empty জাভাস্ক্রিপ্ট Object তৈরি করে। অনেকটা const x = {} এইরকম, যা আসলে Background এ কাজ করে বলে আমরা দেখতে পাই না। দ্বিতীয়ত, এইটি this টিকে সেট করবে খালি বা empty Object টিকে পয়েন্ট করার জন্য যার মধ্যমে আমরা খালি বা empty Object টিতে property বা মেথড যোগ করব। আর অবশেষে, Object টিকে ফাংশন থেকে return করবে। return this এই রকম। এই প্রক্রিয়াটিও আসলে Background এ কাজ করে বলে আমরা দেখতে পাই না।

সুতরাং আমরা এখন CreateCircle Constructor Function কে বিভিন্ন মান বা বিভিন্ন আর্গুমেন্ট দিয়ে কল করে বিভিন্ন circle অবজেক্ট পেতে পারি। চলুন আমরা আরও কিছু circle অবজেক্ট তৈরি করি আমাদের লিখা Constructor Function দিয়ে।

function CreateCircle(radius) {
    this.radius = radius;
    this.draw = function () {
      console.log(`Circle radius is ${this.radius}`);
    };
}

const circle1 = new CreateCircle(5);
console.log(circle1.draw());
const circle2 = new CreateCircle(10);
console.log(circle2.draw());


// output:
// Circle radius is 5
// Circle radius is 10

 

আমরা Constructor Function সম্পর্কে জানলাম। এখন আমরা ক্লাস ব্যবহার করে একই জিনিস করব।

ক্লাসের সুবিধা হল, প্রত্যেকটা ক্লাসের অটোম্যাটিকালি constructor ফাংশন থাকে। যা ক্লাসের ইন্সট্যান্স বা অবজেক্ট তৈরি করে তা রিটার্ন করে। আমরা উপরে যেমন new keyword ব্যবহার করেছি, ক্লাসের ক্ষেত্রেও নতুন অবজেক্ট তৈরির ক্ষেত্রে new keyword ব্যবহার করব। যখনি new keyword দিয়ে ক্লাসের অবজেক্ট ডিক্ল্যেয়ার করি, তখনি constructor ফাংশন কল হয়ে যায়। যখনি constructor কল হয় তখন একটি নতুন অবজেক্ট তৈরি হয় এবং this এর ভ্যালু নতুন অবজেক্টটিতে সেট হয়। তারপর নতুন তৈরি করা অবজেক্ট অটোম্যাটকালি রিটার্ন হয়।

নিচের কোডটি খেয়াল করি। আমরা CreateCircle নামে একটা ক্লাস তৈরি করেছি, যার constructor ফাংশনে radius এর ভ্যালু সেট করেছি। যখনি new keyword ব্যবহার করে আমরা নতুন circle1 অবজেক্ট তৈরি করেছি, তখনি constructor ফাংশন কল হয়েছে এবং আর্গুমেন্টের radius এর ভ্যালু নতুন তৈরি করা অবজেক্টে সেট হয়েছে। এরপর অবজেক্টটি রিটার্ন হয়েছে। এভাবে চাইলে আমরা হাজারটাও circle তৈরি করতে পারব।

class CreateCircle {
   constructor(radius){
      this.radius = radius;
   }
   draw(){
      console.log(`Circle radius is ${this.radius}`)
   }
}

const circle1 = new CreateCircle(5);
circle1.draw()                    // আউটপুটঃ Circle radius is 5

 

  • JS Constructor Pattern Examples
  • JS Constructor Pattern Practices
  • JS Constructor Pattern Interview Questions

৭.৭ “new” কীওয়ার্ড কি? এটা কীভাবে কাজ করে?

জাভাস্ক্রিপ্টে অন্যতম গুরুত্বপূর্ণ একটা টপিক হচ্ছে new কীওয়ার্ড। আমরা কন্সট্রাক্টর প্যাটার্ন ইউজ করার সময় এটি ব্যবহার করি, কিংবা ES6 -এ ক্লাস থেকে নতুন ইন্সট্যান্স/অবজেক্ট তৈরি করার ক্ষেত্রেও ব্যবহার করে থাকি। আজ আমরা জানবো এটি কীভাবে কাজ করে।

আমরা যখন কন্সট্রাক্টর প্যাটার্ন ইউজ করার সময় new কীওয়ার্ড ইউজ করি তখন সাধারণত ৪ তা জিনিস হয়। সেগুলো হচ্ছেঃ

  1. একটি সম্পূর্ণ নতুন অবজেক্ট তৈরি হয়
  2. নতুন অবজেক্টের প্রোটোটাইপ হিসেবে ফাংশনের প্রোটোটাইপ সেট হয়
  3. this এর ভ্যালু হিসেবে নতুন অবজেক্টটি সেট হয়
  4. নতুন তৈরি করা অবজেক্টটি অটোমেটিক রিটার্নড হয়

উপরের কথাগুলো না বুঝে থাকলে আমি বলব জাভাস্ক্রিপ্টের প্রোটোটাইপ এবং কন্সট্রাক্টর ফাংশন টপিকগুলো দেখে আসতে। তাহলে এগুলো বুঝতে সুবিধা হবে।

এখন new কীওয়ার্ড ব্যবহার করে একটি ফাংশন কল করার জন্য, আমাদের আগে একটি ফাংশন ডিক্ল্যেয়ার করতে হবে। চলুন একটি ফাংশন ডিক্ল্যেয়ার করিঃ

function Car(color) {
   this.color = color;
};

 

আমরা Car নামে একটি ফাংশন তৈরি করেছি, যার প্যারামিটার হিসেবে color থাকবে এবং সেটা তার নিজের color প্রোপার্টিতে এসাইন করবে। এখন আমরা যদি new কীওয়ার্ড ব্যবহার করে ফাংশনটি কল করি, তাহলে নিচের জিনিসগুলা হবে।

১। নতুন অবজেক্ট তৈরি হওয়া

let mercedes = new Car("Red");
console.log(typeof mercedes)      // Output: object

 

এখানে আমরা new কীওয়ার্ড ব্যবহার করতেই mercedes অবজেক্ট তৈরি হয়ে গেছে।

২। নতুন অবজেক্টের প্রোটোটাইপ হিসেবে ফাংশনের প্রোটোটাইপ সেট হওয়া

আমরা জানি যে, প্রত্যেকটা ফাংশনেরই prototype প্রোপার্টি থাকে। এখন আমরা যদি Car কন্সট্রাক্টর ফাংশনের প্রোটোটাইপের মধ্যে একটা মেথড ডিক্ল্যেয়ার করি, তাহলে “new” কীওয়ার্ড ব্যবহার করতেই নতুন অবজেক্টের প্রোটোটাইপ প্রোপার্টির সাথে Car ফাংশনের প্রোটোটাইপের লিংক হয়ে যাবে। কথাগুলো শুনতে কিছুটা কঠিন লাগতে পারে। নিচের উদাহরণটি দেখার পরে আশা করি ব্যাপারটা পরিষ্কার হয়ে যাবে।

function Car(color) {
   this.color = color;
};

Car.prototype.getColor = function(){
   console.log("Color of the car is "+this.color)
}

let mercedes = new Car("Red");
mercedes.getColor()         // Output: Color of the car is Red

 

দেখা যাচ্ছে যে, নতুন অবজেক্ট থেকেই আমরা Car এর প্রোটোটাইপের মেথড getColor এক্সেস করতে পারছি। তাই আমরা দেখতে পাচ্ছি যে new কীওয়ার্ড ব্যবহার করলে আমাদের জন্য স্বয়ংক্রিয়ভাবে এই প্রোটোটাইপ লিঙ্কেজ তৈরি হয়।

৩। this এর ভ্যালু হিসেবে নতুন অবজেক্টটি সেট হওয়া

যখনি আমরা new কীওয়ার্ড ব্যবহার করে নতুন অবজেক্ট তৈরি করি, তখনি ফাংশনের ভিতরে this এর ভ্যালু হিসেবে নতুন অবজেক্টটি সেট হবে। এভাবে যদি আমরা হাজারটা অবজেক্টও তৈরি করি, প্রত্যেকবারই this এর ভ্যালু হিসেবে নতুন অবজেক্টই ঠিক হবে। নিচের কোডটি খেয়াল করিঃ

function Car(color) {
   this.color = color;
};

Car.prototype.getColor = function(){
   console.log("Color of the car is "+this.color)
}

let mercedes = new Car("Red");
mercedes.getColor()               // Output: Color of the car is Red
let bmw = new Car("Black");
bmw.getColor()                    // Output: Color of the car is Black

 

যখন আমরা mercedes অবজেক্ট তৈরি করেছি, তখন this এর মান এই অব্জেক্টটিতেই সেট হয়, যার কারণে কালার Red হয়। আবার যখন bmw অবজেক্ট তৈরি করেছি, তখন কালার Black হয়েছে।

৪। নতুন তৈরি অবজেক্ট রিটার্ন হওয়া

এটা বোঝার জন্য আমাদের দুইটা আলাদা ফাংশন ডেফিনিশনের দিকে খেয়াল করতে হবে। প্রথমটায় কোনো return স্টেটমেন্ট থাকবেনা, আর দ্বিতীয়টায় return স্টেটমেন্ট থাকবে। চলুন নিচের কোডটি খেয়াল করিঃ

function Car(color) {
   var object = {
     color: "Green"
   }
   this.color = color;
};

let mercedes = new Car("Red");
console.log(mercedes.color);             // Output: Red
console.log(mercedes instanceof Car)     // Output: true

 

ফাংশনটি একটি অবজেক্ট রিটার্ন করে। তা Car এর ইন্সট্যান্স কিনা তা দেখি এবং আউটপুট true আসে। আসুন এখন ফাংশনটিকে সামান্য পরিবর্তন করি এবং এতে একটি রিটার্ন স্টেটমেন্ট যোগ করি।

function Car(color) {
   var object = {
     color: "Green"
   }
   this.color = color;
   return object;
};

let mercedes = new Car("Red");
console.log(mercedes.color);              // Output: Green
console.log(mercedes instanceof Car)      // Output: false

 

দেখা যাচ্ছে যে এখন আর mercedes অবজেক্ট Car এর ইন্সট্যান্স না। আমাদের তৈরি করা একটি নরমাল অবজেক্ট এক্ষেত্রে রিটার্ন হয়েছে।

আমরা কন্সট্রাক্টর ফাংশনের ক্ষেত্রে new কীওয়ার্ড এর ব্যবহার দেখলাম, এখন দেখব ES6 এর ক্লাসের ক্ষেত্রে new কীওয়ার্ড এর ব্যবহার। ক্লাসের ক্ষেত্রে যখন new কীওয়ার্ড ব্যবহার করা হয় ওই ক্লাসের নতুন কোন ইন্সট্যান্স বা অবজেক্ট তৈরি করতে। নিচের কোডটি একটি নতুন Car অবজেক্ট তৈরি করে, যা সাথে সাথেই Car ক্লাসের কন্সট্রাক্টর মেথড কল করে, আর this এর ভ্যালু হিসেবে অবজেক্টটি সেট হয়। যেহেতু mercedes অবজেক্টটি Car ক্লাস থেকে তৈরি করা হয়েছে, তাই Car ক্লাসের মেথড আর প্রোপার্টিগুলোও mercedes অবজেক্ট থেকে এক্সেস করা যাবে।

class Car {
   constructor(color){
     this.color = color;
   }
   getColor (){
     console.log(this.color)
   }
}

let mercedes = new Car("Red");
mercedes.getColor()              // Output: Red

 

আশা করি new কীওয়ার্ড সম্পর্কে আমাদের ধারণা পরিষ্কার হয়েছে। জাভাস্ক্রিপ্টে এর ব্যবহার আমরা অনেক বেশি দেখব।

  • New keyword Examples
  • New keyword Practices
  • New Keyword Interview Questions

৭.৮ জাভাস্ক্রিপ্টে Abstraction

আমরা ইতিমধ্যেই জানি যে OOP বা অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং মূলত ৪ টা কনসেপ্টের উপর ভিত্তি করে গঠিত। সেগুলো হচ্ছেঃ এবস্ট্রাকশন, এনক্যাপ্সুলেশন, ইনহেরিটেন্স এবং পলিমরফিজম। এই লেখায় আমরা এবস্ট্রাকশন নিয়ে আলোচনা করব।

এবস্ট্রাকশন জাভাস্ক্রিপ্টের একটি অত্যন্ত গুরুত্বপূর্ণ টপিক। Abstraction হলো এমন একটি ধারণা, যেখানে কোনো প্রোগ্রামের অভ্যন্তরীণ বিষয়গুলো ইউজারকে না দেখিয়ে শুধুমাত্র ফাংশনালিটি দেখাবে। যেমনঃ একটা গাড়ী চালাতে হলে আপনার গাড়ীর ইঞ্জিন কিভাবে কাজ করে তার সবকিছু জানার প্রয়োজন নেই। শুধুমাত্র selected কিছু জিনিস জানা দরকার যেমন gas pedal, brake, steering wheel, blinker ইত্যাদি। তাই গাড়ীর ভিতরের ইঞ্জিনিয়ারিং গোপন রাখা হয় ড্রাইভারের থেকে।

ঠিক একই ভাবে আমরা যখন ATM থেকে টাকা তুলি, তখন ATM এ টাকা কীভাবে আসে, মানে ATM এর ভিতরের কাজকর্ম আমাদের জানার দরকার নেই। আমাদের বাটনে ক্লিক করে টাকা তুলতে পারলেই হলো। এটাই হলো এবস্ট্রাকশন, যেখানে প্রোগ্রামের অভ্যন্তরীণ মেকানিজম ইউজারকে না দেখিয়ে শুধুমাত্র তার ফাংশনালিটিগুলো ভিজিবল রাখা হয়। নিচের কোডটি দেখলে আমাদের ধারণা আরও পরিষ্কার হয়ে যাবে।

function Car(name){
   this.name = name;
   this.start = function(){
     // car starting mechanism
     console.log(this.name + " starts");
   }
   this.stop = function(){
     // break mechanism
     console.log(this.name+ " stops");
   }
}

let mercedes = new Car("Mercedes Benz");
mercedes.start();           // Output: Mercedes Benz starts
mercedes.stop();            // Output: Mercedes Benz stops

 

এখানে mercedes নামের নতুন অবজেক্টের গাড়ী কীভাবে স্টার্ট এবং স্টপ ইমপ্লিমেন্টেশন হয় তা জানার দরকার নেই। তার শুধুমাত্র জানা দরকার যে start মেথড কল করলে গাড়ী স্টার্ট হবে, এবং stop মেথড কল করলে গাড়ী স্টপ হবে।

উপরে আমরা কন্সট্রাক্টর ফাংশন দিয়ে উদাহরণ দিয়েছি। আমরা চাইলে তা জাভাস্ক্রিপ্ট ক্লাস দিয়েও করতে পারি।

  • JS Abstraction Examples
  • JS Abstraction Practices
  • JS Abstraction Interview Questions

৭.৯ জাভাস্ক্রিপ্টে প্রাইভেট প্রোপার্টি হাইড করা

অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং কনসেপ্টের সবচেয়ে গুরুত্বপূর্ণ টপিকগুলোর একটা হলো – internal ইন্টারফেস থেকে external ইন্টারফেসকে আলাদা করা। মানে কোডের কঠিন ইমপ্লিমেন্টেশন লজিকগুলোকে আলাদা করা এবং ইউজারকে শুধুমাত্র বাইরের ফাংশনালিটি দেখানো। যেকোনো সফটওয়্যার তৈরির ক্ষেত্রে আমাদের এই কনসেপ্ট জানা দরকার।

চলুন একটা বাস্তব উদাহরণ দিয়ে বোঝা যাক। আমরা কফি মেশিনের সাথে সবাই পরিচিত। কফি বানানোর জন্য আমাদের সাধারণত কি করতে হয়? উপরে দিয়ে কফি, দুধ আর চিনি দিয়ে কয়েকটা বাটনে টিপ দিতে হয়, খুবই সহজ তাইনা?

coffee machine outside

বাহির থেকে দেখতে খুব সিম্পল মনে হলেও ভিতরে দেখতে অনেকটা নিচের ছবির মতো।

coffee machine inside

অনেক জটিল তাইনা? কিন্তু আমাদের কফি বানানোর জন্য ভিতরের এই জটিল কাজকর্ম জানার দরকার নেই। আমরা যদি মেশিনের উপরের কভার খুলে রাখি, তাহলে আমাদের জন্য অনেক কনফিউজিং হয়ে যাবে।

প্রোগ্রামিং এ অবজেক্ট অনেকটা কফি মেশিনের মতোই। জটিল কাজকর্ম আমাদের প্রাইভেট করে রাখতে হয় যাতে ইউজাররা কনফিউজড না হয়ে যায় এবং চাইলেই ভিতরের জটিল লজিক পরিবর্তন না করতে পারে।

অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এ, প্রোপার্টি আর মেথডকে সাধারণত দুই ভাগ্যে ভাগ করা যায়ঃ

Internal interface – যা ক্লাসের অন্যান্য মেথড থেকে এক্সেস করা যাবে, কিন্তু ক্লাসের বাইরে থেকে এক্সেস করা যাবেনা। Internal প্রোপার্টিকে private প্রোপার্টিও বলা হয়।
External interface – ক্লাসের ভিতরে অথবা বাইরে, যেকোনো যায়গা থেকে এক্সেস করা যাবে। External প্রোপার্টিকে public প্রোপার্টিও বলা হয়।

এগুলোকে আমরা আমাদের কফি মেশিনের সাথে তুলনা করতে পারি। ভিতরের জটিল মেশিন হলো internal ইন্টারফেস, আর বাইরের বাটন সুইচ এগুলা হলো external ইন্টারফেস।

কিছু কিছু ল্যাঙ্গুয়েজে protected ফিল্ডও আছে। যা শুধুমাত্র ক্লাসের ভিতরে থেকে এবং যেসকল অবজেক্ট ক্লাস থেকে ইন্সট্যান্স তৈরি করে বানানো হয়েছে তারাই এক্সেস করতে পারবে।
জাভাস্ক্রিপ্টে ল্যাংগুয়েজ লেভেলে protected ফিল্ড বলতে কিছু নেই। কিন্তু আমরা প্রায়ই protected ফিল্ড নিয়ে কাজ করব।

Protected প্রোপার্টিগুলো সাধারণত _ (underscore) দিয়ে শুরু করা হয়। এইটা কোনো বাধ্যতামূলক জিনিস না, কিন্তু জাভাস্ক্রিপ্ট প্রোগ্রামাররা এই নিয়ম মেনে চলে। নিচের কোডটি খেয়াল করি।

class CoffeeMachine {
   waterAmount = 0;
   sugarAmount = 0;
   constructor(power) {
     this.power = power;
     console.log("Created a coffee machine with power: "+power)
   }
}

// কফি মেশিন থেকে নতুন কফি অবজেক্ট তৈরি
let coffee = new CoffeeMachine(100);

// কফিতে পানির পরিমাণ
coffee.waterAmount = 200;

 

এখানে আমরা CoffeeMachine ক্লাস থেকে নতুন একটি coffee নামে ইন্সট্যান্স তৈরি করেছি। আমরা চাইলেই CoffeeMachine ক্লাসের প্রোপার্টিগুলা যেমন waterAmount বা sugarAmount এর মান পরিবর্তন করতে পারি। কারণ বর্তমানে এগুলা public। চলুন আমরা sugarAmount প্রোপার্টিকে protected করে দেখি যাতে বাহির থেকে চাইলেই ইচ্ছামত কেউ পরিবর্তন করতে না পারে। আমরা এখানে getter এবং setter ব্যবহার করে ভ্যালু পরিবর্তন আর ভ্যালু এক্সেস করব। নিচের কোডটি খেয়াল করেনঃ

class CoffeeMachine {
   waterAmount = 0;
   _sugarAmount = 0;
   set sugarAmount(value) {
     if (value < 0) {
       value = 0;
     }
     this._sugarAmount = value;
  }
  get sugarAmount(){
    return this._sugarAmount;
  }

  constructor(power) {
    this.power = power;
    console.log("Created a coffee machine with power: "+power)
  }

}

// কফি মেশিন থেকে নতুন কফি অবজেক্ট তৈরি
let coffee = new CoffeeMachine(100);

// কফিতে চিনির পরিমাণ
coffee.sugarAmount = -100;
console.log(coffee.sugarAmount) // আউটপুটঃ 0

 

এখন প্রোপার্টি এক্সেস আমাদের কন্ট্রোলে আছে। কেউ চাইলেই এখন sugarAmount এর মান শূন্য থেকে কম সেট করতে পারবে না। এভাবেই চাইলে আমরা ক্লাসের কোনো প্রপার্টিকে protected করতে পারি।

Protected ফিল্ড ইনহেরিট হয়। মানে প্যারেন্ট ক্লাসকে ইনহেরিট করে যেসকল চাইল্ড ক্লাস সবাই প্যারেন্টের protected প্রোপার্টি পেয়ে যাবে।

এখন আমরা private প্রোপার্টি নিয়ে নিয়ে জানব। এটি এখনো একটি তৃতীয় স্টেজের প্রপোজাল। কিন্তু Babel এর ল্যাটেস্ট ভার্শনের সহায়তায় আমরা তা ব্যবহার করতে পারব।

Private প্রোপার্টিগুলো # দিয়ে শুরু করতে হয়। শুধুমাত্র ক্লাসের মধ্যে থেকেই এদের এক্সেস করা যায়। নিচের কোডটি খেয়াল করেনঃ

class CoffeeMachine {
   #waterAmount = 0;
   set setWaterAmount(value) {
     this.#waterAmount = value;
   }
}

let coffee = new CoffeeMachine();
coffee.setWaterAmount = 100;
coffee.#waterAmount;        // SyntaxError: Private field '#waterAmount' must be declared in an enclosing class

 

আমরা #waterAmount নামে একটি প্রাইভেট প্রপার্টি সেট করেছি। কেউ চাইলেই ক্লাসের বাইরে থেকে তা সরাসরি এক্সেস করতে পারবেনা, তার জন্য আমাদের getter/setter মেথডের সহায়তা নিতে হবে। নিচের উদাহরণটি দেখলে ব্যপারটা ক্লিয়ার হয়ে যাবে।

class CoffeeMachine {
   #waterAmount = 0;
   set waterAmount(value) {
     this.#waterAmount = value;
   }
   get waterAmount() {
     return this.#waterAmount;
   }
}

let coffee = new CoffeeMachine();
coffee.waterAmount = 10;
console.log(coffee.waterAmount);

 

আমরা জাভাস্ক্রিপ্টের পাবলিক, প্রাইভেট আর প্রোটেক্টেড প্রোপার্টিগুলা সম্পর্কে জানলাম। যা অত্যন্ত গুরুত্বপূর্ণ একটি কনসেপ্ট।

  • JS Encapsulation Examples
  • JS Encapsulation Practices
  • JS Encapsulation Interview Questions

৭.১০ জাভাস্ক্রিপ্টে পলিমরফিজম

পলিমরফিজম শব্দটির বাংলা অর্থ ভিন্নরূপ। অর্থাৎ কোন জিনিসের ভিন্ন ভিন্ন রূপকেই পলিমরফিজম বলে। এখানেও তাই। আমরা বিভিন্ন কাজের জন্য ফাংশন তৈরি করি। এমন ধরণের ফাংশন তৈরি করা লাগতে পারে যেগুলা ভিন্ন ভিন্ন কাজ করে। যেমন একই ফাংশন কিন্তু দুইটি প্যারামিটার নিয়ে একরকম কাজ করে আর তিনটি প্যারামিটার নিয়ে আরেকরকম কাজ করে। আবার এমনো হতে পারে যে অনেকগুলা ফাংশন মিলে একই কাজ করছে। পলিমরফিজমে ফাংশন বা মেথডকে ভিন্ন কাজে ব্যবহার করা হয় সাধারণত দুইটি নিয়মে। সেগুলো হচ্ছেঃ

১। Method Overriding
২। Method Overloading

Method Overriding (মেথড ওভাররাইডিং)

এখানে আমরা জাভাস্ক্রিপ্ট ক্লাসের মাধ্যমে উদাহরণ দিয়েছি, এটা চাইলে প্রোটোটাইপ-বেসড এপ্রোচেও করা যায়। মেথড ওভাররাইডিং-এ চাইল্ড ক্লাস প্যারেন্ট ক্লাসের মেথডকে override করে। মানে চাইল্ড ক্লাস চাইলে প্যারেন্ট ক্লাসের মেথডের কাজের পরিবর্তন করতে পারে। নিচের কোডটি দেখলে আশা করি আপনাদের ধারণা পরিষ্কার হবে।

class Dog {
   constructor(name, age){
      this.name = name;
      this.age = age;
   }
   bark (){
      console.log("Dog barking");
   }
}

class HuskyDog extends Dog {
   constructor(name, age){
      super(name, age);
   }
   bark(){
      console.log("Husky dog barking")
   }
   play () {
      console.log(this.name+ " is playing");
   }
}

const hachi = new HuskyDog("Hachi", 2);
hachi.bark(); // Output: Husky dog barking
hachi.play(); // Output: Hachi is playing

 

এখানে HuskyDog ক্লাসটি প্যারেন্ট ক্লাস Dog কে ইনহেরিট করে। তার মানে প্যারেন্ট ক্লাসের bark মেথডটিও তার হয়ে যাবে। কিন্তু সে তার নিজের ক্লাসের মধ্যেই bark মেথডটি আলাদা ভাবে বানায়। যার কারণে bark মেথডটি এখানে override হয়ে যাবে। এভাবে চাইলে আমরা ইনহেরিটেড মেথড override করতে পারি।

Method Overloading (মেথড ওভারলোডিং)

মেথড অভারলোডিং হলো একই মেথড কে দিয়ে ভিন্নরকম কাজ করানো। যেমনঃ একই নামের ফাংশনের প্যারামিটার যখন দুইটা দিয়ে কল করা হবে তখন সেটি এক কাজ করবে, আবার তিনটা প্যারামিটার দিয়ে কল করা হলে আরেক কাজ করবে। নিচের কোডটি খেয়াল করিঃ

class Dog {
   constructor(name, age){
      this.name = name;
      this.age = age;
   }
   bark (){
      console.log("Dog barking");
   }
   play(){
      console.log(this.name+" is playing")
   }
   play(partner){
      console.log(this.name+" is playing with "+ partner)
   }
   play(partner1, partner2){
      console.log(this.name+" is playing with "+ partner1+ " and "+partner2)
   }
}

const hachi = new Dog("Hachi", 2);
hachi.play();                      // Output: Hachi is playing with undefined and undefined
hachi.play("Broley");              // Output: Hachi is playing with Broley and undefined
hachi.play("Broley", "Bravo");     // Output: Hachi is playing with Broley and Bravo

 

এখানে আমরা একই নামের মেথড play কে দিয়ে ভিন্ন রকমের কাজ করিয়েছি। কিন্তু আউটপুটে undefined হওয়ার কারণ হল, অন্যান্য ল্যাংগুয়েজের মতো জাভাস্ক্রিপ্ট মেথড ওভারলোডিং সাপোর্ট করে না। এইটা কি কারণে হয় বলেন দেখি! এইটা হয় hoisting এর জন্য। কারণ জাভাস্ক্রিপ্টে ফাংশন ডিক্ল্যারেশন hoisted হয়। আমরা চাইলে আমাদের মত করে মেথড ওভারলোডিং ইমপ্লিমেন্ট করতে পারি। কিন্তু তা তুলনামূলক জটিল।

আজ এই পর্যন্তই। আশা করি পলিমরফিজমের ধারণা আমাদের পরিষ্কার হয়েছে।

  • JS Polymorphism Examples
  • JS Polymorphism Practices
  • JS Polymorphism Interview Questions

৭.১১ কীভাবে জাভাস্ক্রিপ্টে Getter এবং Setter ইউজ করতে হয়?

আমরা অবজেক্ট সম্পর্কে জানি। অবজেক্টের মধ্যে দুই ধরণের properties থাকে। প্রথমটা হল data properties, যার সাথে আমরা পরিচিত। আমরা এতক্ষণ পর্যন্ত যেই প্রপার্টিগুলা ইউজ করে আসছি সেগুলো সবই ডাটা প্রোপার্টি।
দ্বিতীয়টি হল accessor properties, যা অবজেক্টে ফাংশন আকারে থাকে এবং ভ্যালু get আর set করতে ব্যবহৃত হয়। আমরা সাধারণত এই দুইটি keyword ব্যবহার করে থাকি accessor properties ডিফাইন করতে।

get – প্রোপার্টির ভ্যালু পাওয়ার জন্য getter মেথড ডিফাইন করতে
set – প্রোপার্টির ভ্যালু ঠিক অথবা পরিবর্তন করার জন্য setter মেথড ডিফাইন করতে

জাভাস্ক্রিপ্ট Getter:
জাভাস্ক্রিপ্টে getter মেথড অবজেক্টের প্রোপার্টিগুলো এক্সেস করতে ব্যবহৃত হয়। নিচের উদাহরণটি লক্ষ করুণঃ

const person = {
   // ডাটা প্রোপার্টি
   name: "Mehedi",
   // এক্সেসর প্রোপার্টি (getter)
   get getName (){
     return this.name;
   }
}

console.log(person.name)            // Output: Mehedi
console.log(person.getName)         // Output: Mehedi

console.log(person.getName())       // TypeError: person.getName is not a function

 

একটা জিনিস লক্ষ করেছেন? যদিও getName একটা মেথড, কিন্তু আমরা এটাকে নরমাল ভ্যারিয়েবল যেভাবে এক্সেস করি সেভাবেই এক্সেস করতে হবে। মেথডের মত এক্সেস করা যাবেনা।

জাভাস্ক্রিপ্ট Setter:
জাভাস্ক্রিপ্টে setter মেথড অবজেক্টের প্রোপার্টিগুলোর ভ্যালু সেট করতে কিংবা চেঞ্জ করতে ব্যবহৃত হয়। নিচের উদাহরণটি লক্ষ করুণঃ

const person = {
   // ডাটা প্রোপার্টি
   name: "Mehedi",
   // এক্সেসর প্রোপার্টি (setter)
   set setName (newName){
     this.name = newName; 
  }
}

console.log(person.name)       // Output: Mehedi
person.setName = "Azad";
console.log(person.name)       // Output: Azad

 

জাভাস্ক্রিপ্ট Object.defineProperty():
আমরা চাইলে Object.defineProperty() ইউজ করে getter এবং setter মেথড ব্যবহার করতে পারি।

const person = {
   name: 'Mehedi'
}

// getting property
Object.defineProperty(person, "getName", {
   get : function () {
     return this.name;
   }
});

// setting property
Object.defineProperty(person, "setName", {
   set : function (value) {
     this.name = value;
   }
});

console.log(person.name);         // Output: Mehedi
person.setName = "Azad"
console.log(person.name);         // Output: Azad

 

আমরা এই উদাহরণে দেখলাম কীভাবে Object.defineProperty() ইউজ করে getter এবং setter মেথড ব্যবহার করতে হয়।

Object.defineProperty(object, property, descriptor) এই মেথডটি তিনটা আর্গুমেন্ট নেয়। সেগুলা হচ্ছেঃ

প্রথম আর্গুমেন্ট হলো অবজেক্টের নাম। আমাদের ক্ষেত্রে সেটা হলো person অবজেক্ট
দ্বিতীয় আর্গুমেন্ট হলো অবজেক্টের এক্সেসর প্রোপার্টির নাম। অর্থাৎ getter এবং setter মেথডের নাম।
তৃতীয় আর্গুমেন্ট হলো একটি অবজেক্ট যা আমাদের  অথবা setter মেথডের ভিতরের কোড।

  • JS Getter/Setter Examples
  • JS Getter/Setter Practices
  • JS Getter/Setter Interview Questions

৭.১২ জাভাস্ক্রিপ্টে প্রোটোটাইপ এবং প্রটোকপিক্যাল ইনহেরিট্যান্স

জাভাস্ক্রিপ্টে প্রোটোটাইপ

জাভাস্ক্রিপ্ট প্রোগ্রামার বা ডেভেলপার হিসাবে Prototype সম্পর্কে পরিষ্কার ধারণা থাকা অতীব জরুরী। তাই চেষ্টা করবো আজকে কিছু ইউজফুল উদারণ দিয়ে Prototype নিয়ে একটু লেখতে। আশা করি, আজকের পর থেকে Prototype নিয়ে কাজ করতে কখনো সমস্যা হবে না। চলুন শুরু করা যাক। নিচের Constructor Function টা লক্ষ্য করুন।

function Car(color, name, manufactureDate) {
   this.color = color;
   this.name = name;
   this.manufactureDate = manufactureDate;
   this.getColor = function () {
     return this.color;
   };
   this.getName = function (){
     return this.name;
   }
   this.getManufactureDate = function(){
     return this.manufactureDate;
   }
}

 

চলুন আমরা firstCar এবং secondCar নামে দুইটি Object তৈরি করি Car Constructor Function ব্যবহার করে।

const firstCar = new Car("red", "Ferrari", "2020");
const secondCar = new Car("yellow", "Lamborgini", "2021");

 

আশা করি এই পর্যন্ত বোঝতে কোন সমস্যা হয় নি। যদি কোন সমস্যা হয়ে থাকে তবে আমাদের Constructor Function এর আলোচনাটি দেখার জন্য অনুরোধ করছি।

উপরের কোডটি লক্ষ্য করলে দেখা যাবে যে, জাভাস্ক্রিপ্ট ইঞ্জিন আমাদের Constructor Function Car এর দুইটি কপি তৈরি করেছে। একটি firstCar আর অন্যটি secondCar এর জন্য। এখন আমরা Constructor Function Car দিয়ে যত Object তৈরি করব Constructor Function Car এর ঠিক তত গুলা কপি তৈরি হবে। একবার ভাবুন তো, প্রত্যেকটি Object এর জন্য একটা ফাংশনের আলাদা আলাদা Instance তৈরি করা মেমোরি অপচয় ছাড়া আর কিছুই নয়। এই সমস্যা আমার খুব সহজে জাভাস্ক্রিপ্টের Prototype এর মাধ্যমে সমাধান করতে পারি।

চলুন Prototype নিয়ে আলোচনা শুরু করা যাক। যখন জাভাস্ক্রিপ্টে একটি Object তৈরি করা হয় ঠিক তখনই জাভাস্ক্রিপ্ট ইঞ্জিন ওই Object এ Prototype নামে একটা Property যোগ করে। মূলত, জাভাস্ক্রিপ্টে যেকোনো Object Type এর মধ্যে Prototype Property আছে। Array Type এর মধ্যে একটা Prototype Property আছে। Date Type এর মধ্যে Prototype Property আছে। এমনকি আমরা যদি কোন Custom Object Type তৈরি করি তবে তার মধ্যেও Prototype Property আছে। আমরা জানি যে, জাভাস্ক্রিপ্টে ফাংশনও এক ধরনের Object. তাই ফাংশনেরও একটি Prototype Property আছে। কোন Object এর Prototype Property টি ব্যবহার করতে হয় functionName.prototype দিয়ে।

এখন চলুন আমরা একটি নাম্বারের Array বানাই যেখানে কিছু সংখ্যা থাকবে। যেমনঃ

const arr = [1, 2,3,4,5];
console.log(arr);

উপরের কোডটি রান করালে দেখব যে, arr এর প্রতিটি ইনডেক্সের মান ব্রাউজারে প্রিন্ট করছে। কিন্তু এর নিচে দেখব, __proto__ নামে একটা Object আছে। এই Object টিকে যদি Expand করি তবে দেখব যে, এইখানে push, concat, indexOf এমন অনেক পরিচিত মেথড বা ফাংশন রয়েছে যা আমরা প্রায়ই Array Manipulation এর কাজ এ ব্যবহার করে থাকি। আমার যদি আরও কোন Array বানাই এবং ওই Array এর __proto__ property টি দেখি তবে দেখব যে আগের মত অনেক পরিচিত মেথড বা ফাংশন এখানেও রয়েছে। কিন্তু এই মেথড বা ফাংশন গুলো কোথা থেকে এলো। আমরা তো কোথাও এইগুলা Define বা Declare করি নি।

একই constructor Function ব্যবহার করে তৈরি হওয়া সমস্ত Object একই Prototype Object টিকে Share করে। সুতরাং, Array Constructor Function ব্যবহার করে তৈরি করা সব Array তাই একই Prototype Object কে Share করবে। তাই যখনই আমরা একটা Array Declare করি ঠিক তখনই Array এর জন্য নির্ধারিত Prototype Object টি Array এর ভিতর Assign হয়ে যায়। আর Array এর জন্য নির্ধারিত Prototype Object টির ভিতর push, concat, indexOf এর মত অনেক পরিচিত মেথড বা ফাংশন আগে থেকে লিখা আছে। তাই আমরা যত খুশি Array Type ভেরিয়েবল Declare করি না কেন, সব কয়টার __proto__ ভিতর পূর্ব নির্ধারিত মেথড বা ফাংশন গুলো থাকবে।

এখন তাহলে চলুন আমরা আমাদের Car Constructor Function এর মধ্যে থাকা getColor, getName, getManufactureDate মেথডগুলোকে সরিয়ে Car Constructor Function এর Prototype এর মধ্যে ঢোকাই; যাতে করে Car Constructor Function দিয়ে তৈরি সব Object এর মধ্যে মেথডগুলোকে automatically চলে আসে।

function Car(color, name, manufactureDate) {
   this.color = color;
   this.name = name;
   this.manufactureDate = manufactureDate;
}

Car.prototype.getColor = function () {
   return this.color;
};
Car.prototype.getName = function () {
   return this.name;
};
Car.prototype.getManufactureDate = function () {
   return this.manufactureDate;
};

const firstCar = new Car("red", "Ferrari", "2020");
console.log(firstCar);

const secondCar = new Car("Yellow", "Lamborgini", "2021");
console.log(secondCar);

উপরের কোডটি যদি আমরা ব্রাউজার এ গিয়ে Output দেখি তবে দেখব যে, আমাদের Car Constructor Function এর ভিতর এখন আর মেথডগুলো নেই। মেথডগুলো এখন __proto__ এর ভিতর চলে গিয়েছে যা Car Constructor Function থেকে তৈরি সব Object ই automatically পেয়ে যাবে। প্রতিটি Object Instance এর ভিতর থাকলে যে মেমোরি অপচয় হওয়ার কথা ছিল টা এখন আর হচ্ছে না।

  • JS Prototype Examples
  • JS Prototype Practices
  • JS Prototype Interview Questions

 

জাভাস্ক্রিপ্টে প্রোটোটাইপ এবং প্রটোকপিক্যাল ইনহেরিট্যান্স

সহজভাবে বলতে গেলে Prototypical Inheritance বলতে একটি Object যখন অন্য একটি Object এর প্রপার্টিকে অ্যাক্সেস করতে পারে তাকেই বুঝায়। আমরা জানি যে, জাভাস্ক্রিপ্টের Prototype এর মধ্যে যে কোন Object এ নতুন প্রপার্টি বা মেথড যোগ করা যায়; আমারা তখন আমাদের জাভাস্ক্রিপ্ট কোডে Prototype থেকে এই প্রপার্টিগুলো Inherite করার জন্য বলে দিতে পারি। একটি Object অন্য Object এর প্রপার্টি বা মেথডগুলোকে পুনরায় ব্যবহার করতে Prototypical Inheritance সাহায্য করে।

সকল জাভাস্ক্রিপ্ট Object ই কোন না কোন প্রপার্টি বা মেথড prototype থেকে Inherit করে থাকে। উদাহরণস্বরূপ,

  1. Date Object, Date.prototype থেকে Inherit করে থাকে।
  2. Array Object, Array.prototype থেকে Inherit করে থাকে। আর এই Prototype chain এর সবার উপর থাকে Object.prototype. Date Object, Array Object সবাই Object.prototype কে Inherit করে।

চলুন, এখন সরাসরি Prototypical Inheritance বুঝার চেষ্টা করি কিছু practical উদাহরন এর মাধ্যমে।

আসুন, একটি Rectangle constructor তৈরি করা যাক।

function Rectangle(width, height) {
   this.width = width;
   this.height = height;
}

 

এখন যদি আমারা Rectangle constructor দিয়ে একটা Object তৈরি করতে চাই তবে কি করে করব। নিশ্চয়ই মনে আছে।

let rect = new Rectangle(3, 4);
rect.width;               // Now the width of Rectangle is 3
rect.height;              // And the height of that rectangle is 4

এখন আমরা এই Rectangle constructor এর মধ্যে একটা মেথড তৈরি করব। মেথডটির নাম area দেয়া যেতে পারে।

Rectangle.prototype.area = function () {
   return this.width * this.height;
};

 

এখন আমরা ইচ্ছে করলেই Rectangle Object এর area মেথডটি ব্যবহার করতে পারি।

var rect = new Rectangle(3, 4);
rect.area();            // 12

 

আশা করি এই পর্যন্ত বুঝতে আমাদের কোন সমস্যা হয়ে নি। চলুন আমরা square constructor এর মাধ্যমে একটি Object তৈরি করি।

function Square(length) {
   this.width = this.height = length;
}

 

আমরা সবাই জানি যে, Square আসলে একটা বিশেষ ধরনের Rectangle। তাহলে Rectangle এর বৈশিষ্ট্যগুলোও Square এর মধ্যে থাকা উচিত। কিন্তু কি করে এই কাজটি করব? যদি আমাদের মনে থেকে থাকে তবে আমরা জানি যে, Object.create() দিয়ে আমারা একটি খালি বা Empty Object তৈরি করতে পারি। তাহলে একটা কাজ করলে কেমন হয়, Square এর prototype এর একটা Object তৈরি করি Reactangle এর prototype কে প্যারেন্ট ধরে।

Square.prototype = Object.create(Rectangle.prototype);

 

এখন Square এর prototype এর মধ্যে Rectangle.prototype এর বৈশিষ্ট্যগুলো চলে এসেছে। সুতরাং, Square এর সকল Instance এর Prototype এর মধ্যেও এই বৈশিষ্ট্যগুলো থাকবে। তাহলে চলুন দেখি সবকিছু ঠিকঠাক কাজ করছে কি না।

var square = new Square(4);
square.area();       // 16

 

উপরের কোডটি যদি একটু লক্ষ্য করে দেখুন তবে থেখা যাবে যে, আমরা square নামে যে Object টি তৈরি করেছি তার মধ্যে area মেথডটি চলে এসেছে। এটাই আসলে Prototypical Inheritance। এখন আমরা যদি চাই, তবে square এর মধ্যে শুধুমাত্র তার নিজের কিছু মেথড বা প্রপার্টি যোগ করতে পারি। চলুন তাহলে করা যাক,

Square.prototype.diagonal = function () {
   return Math.sqrt(this.area() * 2);
};

 

একটা বিষয় মাথায় রাখা জরুরী, তা হল একটি Object কখনও একাধিক Prototypes Inherit করতে পারে না।

৭.১৩ জাভাস্ক্রিপ্টে মাল্টি লেভেল ইনহেরিট্যান্স

আমরা জাভাস্ক্রিপ্টে prototypical ইনহেরিট্যান্স নিয়ে জেনেছি। আজ আমরা মাল্টি লেভেল ইনহেরিট্যান্স নিয়ে আলোচনা করব। আমরা জিনিসটা এইভাবে চিন্তা করতে পারি, আমাদের দাদার থেকে আমাদের বাবা সম্পতি পেয়েছে, আবার আমাদের বাবার সম্পত্তি আমরা পাবো। মাল্টি লেভেল ইনহেরিট্যান্সও তাই। আমরা প্রথমে প্রোটোটাইপ চেইন ব্যবহার করে মাল্টি লেভেল ইনহেরিট্যান্স দেখব। তারপর জাভাস্ক্রিপ্ট ক্লাস দিয়ে একই জিনিস করব।

/*
আমরা এখানে জাভাস্ক্রিপ্টের প্রোটোটাইপ চেইন ব্যবহার করে মাল্টি লেভেল ইনহেরিট্যান্স ইমপ্লিমেন্ট করেছি।
*/

let grandfather = {
   grandfatherProperty : function(){
     console.log("Grandfather's property")
   }
}

let father = {
   __proto__ : grandfather,
   fatherProperty : function(){
     console.log("Father's property")
   }
}

let son = {
   __proto__ : father,
   sonProperty : function(){
     console.log("Son's Property")
   }
}

son.grandfatherProperty();          // আউটপুটঃ Grandfather's property

 

উপরের কোডটি খেয়াল করি। prototypical ইনহেরিট্যান্স সম্পর্কে জানলে জিনিসটা আমাদের খুবই সহজ। যারা জানেন না তাদেরকে prototypical ইনহেরিট্যান্স সম্পর্কে দেখে আসতে বলব। উপরের কোডটিতে father অবজেক্ট grandfather এর সবকিছু ইনহেরিট করে, আবার son অবজেক্ট father অবজেক্টের সবকিছু ইনহেরিট করে। কাজেই, son অবজেক্ট থেকে চাইলেই father এবং grandfather এর সবকিছু এক্সেস করা যাবে।

আমরা এতক্ষণ প্রোটোটাইপ চেইন ব্যবহার করে মাল্টি লেভেল ইনহেরিট্যান্স সম্পর্কে জানলাম। এখন আমরা একই জিনিস ES6 ক্লাস দিয়ে দেখব।
আমরা জানি, জাভাস্ক্রিপ্টে প্যারেন্ট ক্লাস থেকে ইনহেরিট করার জন্য চাইল্ড ক্লাসকে এক্সটেন্ড করতে হয়। তাহলে প্যারেন্ট ক্লাসের পাবলিক আর প্রোটেক্টেড প্রোপার্টিগুলা চাইল্ড ক্লাসও পেয়ে যায়।

class Grandfather {
   grandfatherProperty(){
     console.log("Grandfather's property")
   }
}

class Father extends Grandfather {
   fatherProperty(){
     console.log("Father's property")
   }
}

class Son extends Father {
   sonsProperty(){
     console.log("Son's property")
   }
}

const son = new Son();
son.grandfatherProperty()          // আউটপুটঃ Grandfather's property

 

দেখা যাচ্ছে, son নামের একটি instance তৈরি করা হয়েছে Son ক্লাস থেকে। এই অবজেক্টটি থেকে আমরা তার প্যারেন্ট এবং গ্র্যান্ডপ্যারেন্টের প্রপার্টি এক্সেস করতে পারছি। এটাই মাল্টি লেভেল ইনহেরিট্যান্স। আশা করি জাভাস্ক্রিপ্টে মাল্টি লেভেল ইনহেরিট্যান্স সম্পর্কে আমাদের ধারণা পরিষ্কার হয়েছে।

  • Multilevel Inheritance Examples
  • Multilevel Inheritance Practices
  • Multilevel Inheritance Interview Questions