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

 

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

জাভাস্ক্রিপ্ট প্রোগ্রামার বা ডেভেলপার হিসাবে 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 করতে পারে না।

 
উদাহরন
  • নিচের উদাহরণটি খেয়াল করি।

function Student() {
    this.name = 'John';
    this.gender = 'M';
}

Student.prototype.age = 15;

var studObj1 = new Student();
alert(studObj1.age); // 15

var studObj2 = new Student();
alert(studObj2.age); // 15
  • আমরা চাইলে এভাবেও প্রোটোটাইপ ব্যবহার করতে পারি: 

function Student() {
    this.name = 'John';
    this.gender = 'M';
}

var studObj = new Student();

console.log(Student.prototype); // object
console.log(studObj.prototype); // undefined
console.log(studObj.__proto__); // object

console.log(typeof Student.prototype); // object
console.log(typeof studObj.__proto__); // object

console.log(Student.prototype === studObj.__proto__ ); // true
  • যেহেতু অবজেক্টের প্রোটোটাইপ ইনভিজিবল, তাই Object.getPrototypeOf(obj) ব্যবহার করে প্রোটোটাইপ অবজেক্ট এক্সেস করতে হয়।

function Student() {
    this.name = 'John';
    this.gender = 'M';
}

var studObj = new Student();

Student.prototype.sayHi= function(){
    alert("Hi");
};

var studObj1 = new Student();
var proto = Object.getPrototypeOf(studObj1);  // returns Student's prototype object
            
alert(proto.constructor); // returns Student function
  • আমরা চাইলে প্রোটোটাইপ পরিবর্তনও করতে পারি।

function Student() {
    this.name = 'John';
    this.gender = 'M';
}

Student.prototype.age = 15;

var studObj1 = new Student();
alert('studObj1.age = ' + studObj1.age); // 15

var studObj2 = new Student();
alert('studObj2.age = ' + studObj2.age); // 15

Student.prototype = { age : 20 };

var studObj3 = new Student();
alert('studObj3.age = ' + studObj3.age); // 20

alert('studObj1.age = ' + studObj1.age); // 15
alert('studObj2.age = ' + studObj2.age); // 15

 

 

এসো নিজে করি
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?

function Person () {
    this.name = 'John',
    this.age = 23
}

const person1 = new Person();
const person2 = new Person();

Person.prototype.gender = 'male';

console.log(Person.prototype);

console.log(person1.gender);
console.log(person2.gender);
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?
function Person () {
    this.name = 'John',
    this.age = 23
}

const person1 = new Person();
const person2 = new Person();

Person.prototype.greet = function() {
    console.log('hello' + ' ' +  this.name);
}

person1.greet(); 
person2.greet();
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?
function Person() {
    this.name = 'John'
}

Person.prototype.age = 20;

const person1 = new Person();

console.log(person1.age); 

Person.prototype = { age: 50 }

const person3 = new Person();

console.log(person3.age);
console.log(person1.age);
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?
function Person () {
    this.name = 'John'
}

Person.prototype.age = 24;

const person = new Person();

console.log(person.__proto__);  
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?
function Student() {
    this.name = 'John';
    this.gender = 'M';
}

var studObj = new Student();

console.log(Student.prototype === studObj.__proto__ );