জাভাস্ক্রিপ্ট টিউটোরিয়াল-শিখুন গল্পে গল্পে সাথে 1100+ Exercise

  • জাভাস্ক্রিপ্ট পরিচিতি-Introduction to JavaScript
  • প্রোগ্রামিং শুরু করতে কতটুকু গণিত লাগে?
  • প্রোগ্রামিং শুরু করতে কতটুকু ইংরেজি জানা লাগে?
  • ভালো প্রোগ্রামার কিভাবে হবো? [+৭টি গুরুত্বপূর্ণ টিপস]
  • সেইম ড্রেসে class পার্টি
  • Method তুমি কার? ক্লাসের না আমার?
  • আজ থেকে তুই ত্যাজ্য Inheritance
  • Prototypical Chain-এর সিক্রেট রিলেশন

Prototypical Chain-এর সিক্রেট রিলেশন


JavaScript - The prototype chain in depth | Code, Thoughts ...


মানুষ সামাজিক জীব। সে একাকি বাস করতে পারে না। সমাজবদ্ধ হয়ে বাস করা তার জন্মগত স্বভাব। মানুষের সমাজবদ্ধতার বড় কারণ পারস্পরিক সহযোগিতা। এককভাবে কোনো মানুষই তার সমস্ত চাহিদা পূরণ করতে পারে না। বিভিন্নমুখী চাহিদার জন্য মানুষ একে অপরের ওপর নির্ভরশীল। এই বিষয়ে সমাজবিজ্ঞানী এরিস্টটল বলেন—


আচ্ছা থাক, আপাতত সমাজবিজ্ঞানী এরিস্টটল কী বলছে, সেটা একটু সাইডে রাখ। 


তবে জাভাস্ক্রিপ্টের বিশেষ জ্ঞানীরা বলে— জাভাস্ক্রিপ্টের বেশির ভাগ জিনিসই অবজেক্ট। শুধু কয়েকটা প্রিমিটিভ টাইপ ছাড়া বাকিসব কিছুই অবজেক্ট। অবজেক্ট নিজে তো অবজেক্ট। এই ছাড়াও অ্যারে একধরনের অবজেক্ট, ফাংশন নিজেও একটা অবজেক্ট। set, map, promise, JSON, arguments, Date, RegEx এইগুলা সবই অবজেক্ট এবং এরা সবাই সামাজিক জীব। তারা একে অপরকে ছাড়া বাঁচতে পারে না। 


তা ছাড়া একেকটা অবজেক্টও নিজেদের বিভিন্ন লেয়ার বানিয়ে রাখে, যাতে কমন জিনিসগুলো সবাই শেয়ার করতে পারে। এই শেয়ার করার প্রসেস হচ্ছে inheritance বা উত্তরাধিকার। জাভাস্ক্রিপ্ট নিজে নিজে প্রোটোটাইপিক্যাল ইনহেরিটেন্স (prototypical inheritance)-এর মাধ্যমে এক একটা অবজেক্টের মধ্যে সিক্রেট রিলেশন তৈরি করে। যাতে এক অবজেক্ট আরেক অবজেক্টের প্রোপার্টি আর মেথড শেয়ার করতে পারে। আর এই জিনিসটা ভিতরে ভিতরে জাভাস্ক্রিপ্ট করে "prototype chain"-দিয়ে। 


অবজেক্টের সিক্রেট প্রোপার্টি

জাভাস্ক্রিপ্টের প্রত্যেকটা অবজেক্টের ভিতরে একটা "hidden link" থাকে, যেই লিঙ্ক দিয়ে সে অবজেক্টের সাথে কানেকশন তৈরি করে। এই ইন্টারনাল প্রোপার্টি হচ্ছে [[Prototype]]। এটা জাভাস্ক্রিপ্টের ভিতরের জিনিস। সরাসরি তুই এই [[Prototype]] দেখতে পারবি না। কারণ, এটা জাভাস্ক্রিপ্টের ইঞ্জিনের জন্য থাকে। তবে এইটার মান আমরা দুইভাবে পাইতে পারি— 


১. অবজেক্টের নামের পর __proto__ (দুইটা আন্ডারস্কোর চিহ্ন, তারপর proto-এর পর দুইটা আন্ডারস্কোর চিহ্ন) এই জিনিস ইদানিংকালে বেশি ইউজ করা হয় না। 

২. সেইম জিনিস পাওয়ার জন্য আরও ভালো অপশন হচ্ছে, Object লিখে তারপর ডট চিহ্ন দিয়ে getPrototypeOf লিখে ব্র্যাকেটের মধ্যে যে অবজেক্টের prototype পেতে চাস, সেই অবজেক্টের নাম দিয়ে দিবি এইভাবে Object.getPrototypeOf(obj) । এইটা এখন বেশি ইউজ হয়।


অর্থাৎ জাভাস্ক্রিপ্ট অবজেক্টের সিক্রেট প্রোপার্টি [[Prototype]] দিয়ে সে অন্য অবজেক্ট বা তার প্রোটোটাইপের সাথে লিঙ্ক করে। 


প্রোটোটাইপ চেইন 

JavaScript-এ প্রত্যেক অবজেক্টের একটা প্রোটোটাইপ থাকে, এই প্রোটোটাইপ অন্য আরেকটা অবজেক্টের সাথে কানেকশন তৈরি করে। তুই যখন কোনো একটা অবজেক্টের কোনো প্রোপার্টি বা মেথড অ্যাক্সেস করার চেষ্টা করবি, সে প্রথমে সেই অবজেক্টের মধ্যে সেই প্রোপার্টি বা মেথড খুঁজবে। যদি পেয়ে যায়, তাহলে সেটা তোকে দিয়ে দিবে। আর যদি না পায়, তখন সে চেইন ধরে ওপরে উঠা শুরু করবে। 


এই ওপরে উঠার সিস্টেম হচ্ছে— কোনো মেথড বা প্রোপার্টি না পেলে সে সেই অবজেক্টের প্রোটোটাইপের কাছে যাবে। সেই প্রোটোটাইপ নিজেও কিন্তু আরেকটা অবজেক্ট। সেটার মধ্যে সেই সেই প্রোপার্টি বা মেথড খোঁজে। যদি পেয়ে যায়, তাহলে দিয়ে দিবে। আর যদি না পায়, তাহলে সেই অবজেক্টের প্রোটোটাইপে গিয়ে খুঁজবে। 


এভাবে একটা অবজেক্ট থেকে তার প্রোটোটাইপ ধরে ধরে ওপরের অবজেক্টে খুঁজতে থাকবে। পেয়ে গেলে তো হয়ে গেল, আর না পেলে ওপরের দিকে উঠতেই থাকবে। একটা সময় গিয়ে দেখবে, আর কোনো প্রোটোটাইপ নাই। প্রোটোটাইপ অবজেক্ট একসময় গিয়ে null হয়ে গেছে। তখন সে ওই প্রোপার্টি নাই বা মেথড নাই, সেটা বলে দিবে।


এইটাই হচ্ছে জাভাস্ক্রিপ্টের প্রোটোটাইপিক্যাল ইনহেরিটেন্সের রহস্য। 


চেইন ধরে মারো টান 

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


  const mouse = {
    name: 'Jerry not Tom'
  }

  console.log(mouse.__proto__)

Output:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
toString: ƒ toString()
__proto__: (...)


আরেকবার অবজেক্টের দিকে খেয়াল কর। খুবই সিম্পল আর নিষ্পাপ অবজেক্ট। জাস্ট একটা প্রোপার্টি আছে name নামে। কোনো মেথড নাই। এখন তুই যদি mouse.toString লিখে ফেলস, তাহলে এই toString কই থেকে আসবে? হাওয়া থেকে আসবে? মোটেও না; বরং সেটা আসবে mouse.__proto__ থেকে। এইটা তুই সেট করে দিস নাই। এইটা জাভাস্ক্রিপ্ট ভিতরে ভিতরে সেট করে দেয়। 


  const mouse = {
    name: 'Jerry not Tom'
  }
  console.log(mouse.toString())

Output: '[object Object]'

তোর অবজেক্টের মধ্যে toString নাই, তারপরেও সেটা পেয়ে গেছস। কারণ, mouse অবজেক্টের প্রোটোটাইপের মধ্যে toString ছিল। আবার তুই যদি mouse.friend খুঁজিস, সেটা কিন্তু পাবি না। কেন পাবি না। কারণ, সে প্রথম মেইন অবজেক্টের মধ্যে খুঁজবে। না পেলে mouse.__proto__ এর মধ্যে খুঁজবে। সেখানে না পেলে mouse.__proto__ এর __proto__ অর্থাৎ mouse.__proto__.__proto__ কে যখন খুঁজবে, তখন দেখবে mouse.__proto__.__proto__ হচ্ছে null আর তখন বলে দিবে, এইটা নাই। কারণ, সে পুরা প্রোটোটাইপ চেইন খুঁজে দেখছে, কোথাও এইটা নাই। 

  console.log(mouse.__proto__.__proto__)

Output: null


extends আর super-এর ইনহেরিটেন্স 

তুই যখন একটা প্যারেন্ট ক্লাসকে extend করে চাইল্ড ক্লাস বানাস, তখন কিন্তু ভিতরে ভিতরে চাইল্ড ক্লাস থেকে যে অবজেক্ট বানানো হবে, তার প্রোটোটাইপ হিসেবে প্যারেন্ট ক্লাসের অবজেক্টকে সেট করে ফেলস। এইটা তুই ওপরে ওপরে বুঝবি না। ভিতরে ভিতরে হয়ে যাবে। তবে তুই চাইলে দেখে নিতে পারস। 


প্রথমে তুই ভদ্রভাবে একটা প্যারেন্ট ক্লাস আর একটা চাইল্ড ক্লাস বানিয়ে ফেল। প্যারেন্ট ক্লাসের নাম দিবি Vehicle, আর চাইল্ড ক্লাসের নাম দিবি Bus। এই দুইটার মধ্যে ইনহেরিটেন্স কাজ করবে। এরপর তুই একটা bus অবজেক্ট বানিয়ে ফেলবি। সেই অবজেক্টের নাম দিলি cityBus, আর সবার শেষে দুইভাবে চেক করে দেখ, cityBus-এর প্রোটোটাইপে কে আছে। একবার চেক কর Object.getPrototypeOf(cityBus) দিয়ে আবার চেক কর cityBus.__proto__ দিয়ে । দুইটাই দেখবি Vehicle-কে বুঝাচ্ছে। 


  class Vehicle {
   constructor(brand, model, fuelType) {
    this.brand = brand;
    this.model = model;
    this.fuelType = fuelType;
   }
  }

  // Child Class: Bus
  class Bus extends Vehicle {
   constructor(brand, model, fuelType, capacity) {
    super(brand, model, fuelType);
    this.capacity = capacity;
   }
  }
  const cityBus = new Bus("Volvo", "B11R", "Diesel", 50);
  const proto1 = Object.getPrototypeOf(cityBus);
  console.log(proto1);
  const proto2 = cityBus.__proto__;
  console.log(proto2);



Output: 
Vehicle { }
Vehicle { }


আগে গেলে বাঘে খায় 

একটু আগে দেখছিলি, mouse অবজেক্টের ওপরে toString করলে সে তার প্রোটোটাইপের toString ইউজ করে। তুই এইটা জানস, তুই যদি mouse অবজেক্টের ওপরে toString মেথড খুঁজস, তাহলে সে প্রথমে mouse অবজেক্টে খুঁজবে, না পেলে সে তার প্রোটোটাইপে যাবে। তাইলে তুই একটা চালাকি করতে পারস। তুই চাইলে তোর mouse অবজেক্টের মধ্যেই একটা toString মেথড লিখে দিতে পারস। তাহলে জাভাক্রিপ্ট mouse-এর মধ্যে toString পেয়ে গেলে সে আর প্রোটোটাইপে খুঁজতে যাবে না। 


  const mouse = {
    name: 'Jerry not Tom',
    toString: function() {
      return `This is a mouse named: ${this.name}`;
    }
  };

  console.log(mouse.toString());

Output: This is a mouse named: Jerry not Tom


এইভাবে তুই চাইলে জাভাস্ক্রিপ্টের কোনো বিল্ট-ইন মেথডকে নিজের মতো করে কাস্টমাইজ করে নিতে পারবি। এমনকি প্যারেন্ট ক্লাসে কোনো প্রোপার্টি বা মেথড থাকলেও দরকার হলে চাইল্ড ক্লাসে ইচ্ছামতো কাস্টমাইজ করে নিতে পারবি। 


প্রোটোটাইপ ইনহেরিটেন্সের মূল পয়েন্ট


প্রতিটি অবজেক্টের প্রোটোটাইপ থাকে: JavaScript-এ প্রতিটি অবজেক্টের একটা অভ্যন্তরীণ লিঙ্ক থাকে, যাকে প্রোটোটাইপ বলা হয়। এটা অন্য একটা অবজেক্টের রেফারেন্স।


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


Object.create(): একটা সময় Object.create দিয়ে প্রোটোটাইপিক্যাল ইনহেরিটেন্স সেট করা হতো। তখন Object.create লিখে সেটার মধ্যে আরেকটা অবজেক্ট দিয়ে দিলে এই দুইটার মধ্যে একটা ইনহেরিটেন্স তৈরি হয়ে যেত। তবে ES6-এ class, extends, super এইসব আসার পর আর কেউ Object.create দিয়ে ইনহেরিটেন্স তৈরি করে না। 




Practice: 

  1. জাভাস্ক্রিপ্টে ইনহেরিটেন্স কীভাবে কাজ করে?
  2. প্রোটোটাইপিক্যাল ইনহেরিটেন্স কী জিনিস?
  3. একটা person অবজেক্ট বানিয়ে ফেল, যেটাতে শুধু name প্রোপার্টি আছে। এখন চেক কর, এর প্রোটোটাইপে কিছু আছে কি না। থাকলে সেখান থেকে যেকোনো একটা মেথড ইউজ করে দেখ, কী আউটপুট দেখায়। 
  4. তুই student নামে একটা অবজেক্ট বানাইলি। এই অবজেক্টের মধ্যে কোনো toString নামে মেথেড লিখলি না। তাহলে তুই কি student.toString() ইউজ করতে পারবি? কেন পারবি?


Previous PageNext Chapter