ক্লোজার ফাংশন(Closures Function)

ক্লোজার ফাংশন (Closures Function) মানে হচ্ছে কোন কিছু কে আবদ্ধ করে রাখা। আরো যদি সহজ ভাষায় বলি কোন কিছু নিজের একটা প্রাইভেট বা ব্যাক্তিগত বক্স করে সেই বক্সে রাখা। এখন কথা হচ্ছে কেন এমন জিনিস জাভাস্ক্রিপ্টে আসল কি কারনে আসল। চলুন একটু বিষয়টা বুঝার চেষ্টা করি।

চলুন প্রথমে কিছু কোড দেখে নেই।

let value = 1
function multiply(){
   value = value * 2;
   console.log(value)
}  
multiply() // output: 2
multiply() // output: 4
multiply() // output: 8
console.log(value) // 8

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

function multiply(){
   let value = 1
   value = value * 2;
   console.log(value)
}  
multiply() // output : 2
multiply() // output : 2
console.log(value) // output: ReferenceError: value is not defined

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

যাই হোক আমরাও গভীরে যায় এখন। প্রথমেই জেনে নেই জীবনকাল কি ?

ভেরিয়েবল এর জীবনকাল

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

আমরা জানি ভেরিয়েবল দুই ধরনের হতে পারে একটা গ্লোবাল আরেকটা হচ্ছে লোকাল।

গ্লোবাল ভেরিয়েবল এর জীবনকাল কি ?

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

NOTE: জাভাস্ক্রিপ্টের গ্লোবাল ভেরিয়েবল আর নোড জে এস এর ভেরিয়েবল দুইটার মধ্য একটু পার্থক্য আছে।

এবার আপনার মনে হয়ত প্রশ্ন জাগছে তাহলে লোকাল ভেরিয়েবল এর ক্ষেত্রে কি হবে?

লোকাল ভেরিয়েবল এর জীবনকাল কি?

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

NOTE: ফাংশন যেহেতু গ্লোবাল স্কোপে থাকে সেহেতু আপনি ফাংশন কে গ্লোবাল স্কোপে পাবেন কিন্তু যখন এক্সিকিউশন হবে তখন ওর ভিতরে থাকে ভ্যারিয়েবল গুলো মেমোরি দখল করে নেয়।

এবার আবার আমাদের আগের কোডটা একটু লক্ষ্য করি। আমরা দ্বিতীয় কোডটা লিখেছি সেই কোড টা কিন্তু ফাংশন স্কোপের ভেরিয়েবল ব্যাবহার করছে। যার কারণে আমরা যখন আসলে দ্বিতীয়বার কল করছি আমাদের চাহিদা অনুযায়ী আউটপুট পাচ্ছি না। কারন সে যখন একবার এক্সিকিউট হয়ে যাচ্ছে তার ভেরিয়েবল লাইফটাইম শেষ হয়ে যাচ্ছে দ্বিতীয় বার যখন কল হচ্ছে সে আসলে আগের ভেরিয়েবলের কোন অস্তিত্ব পাচ্ছে না। যার কারণে আমি দ্বিতীয় বার যখন আশা করছি ৪ পবো পাচ্ছি না। তাছাড়া আমি গ্লোবাল লোকেশন আছে কিনা সেইটা খুজে দেখলাম সে ক্ষেত্রে সে আমাকে ReferenceError: value is not defined নামে একটা এরর দিল। এর মানে হলো সে আসলে খুজে পাচ্ছে না মেমোরি তে মানে তার মেমোরি লোকেশন রেফার করতে পারছে না । তাহলে এইটা একটা সমস্যা আমি যদি চাই যে আমার ফাংশনের ভিতরে আমি একটা কাজ করব যেইটা আমার কাজ গুলোকে মনে রাখবে এবং পরে আমি ঐ ভ্যালু এর উপর ভিত্তি করে আমার পরবর্তী সিদ্ধান্ত নিব। এইটা সমাধান করব কিভাবে?

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

তাহলে আমার ফাংশন টা যদি একটা বক্স কল্পনা করি আর সেইটা যদি আরেকটা বক্স কে রাখে মানে আরেকটা ফাংশন কে তাহলেই তো সমস্যা সমাধান হয়ে যায় তাই না।

চলুন আরেকটা কোড দেখে নেই।

function multiply() {
  let value = 1;
  function mul() {
     value = value * 2;
  }
  mul();  
  return value; 
}
const mul1 = multiply()
const mul2 = multiply()
console.log(mul1, mul2) //output 2 2

কি হলো ? আমি বক্স বানালাম তো সমস্যা সমাধান হলো না কেনো? চলুন একটু ভিতরে কোড গুলো দেখি কেনো হলো না।

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

তাহলে কি ভুল ছিল?

আসুন তার আগে আরেকটা কোড দেখে নেই।

function multiply () {
  let value = 1;
  function mul() {
      value = value * 2; 
      return value
  }
 return mul
};

const mul = multiply()
console.log(mul()) // 2
console.log(mul()) // 4
console.log(mul()) // 8

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

NOTE: বক্স বলতে এখানে ফাংশন কে বুঝানো হয়েছে

MDN এর অফিসিয়াল সংজ্ঞা অনুযায়ী-

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

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

চলুন আরো একটা উদাহরন দেখে নেই এইটা কিন্তু আমি ব্যাখা করব না আপনাকে বুঝে নিতে হবে এবং বুঝা হলে আমাকে মেইল করে জানান আপনি কি বুঝেছেন। আপনার মতামত আমার অনুপ্রেরনা হবে সেইটা হোক ভাল/খারাপ।

function wrapValue(n) {
  let local = n;
  return () => local;
}

let wrap1 = wrapValue(1);
let wrap2 = wrapValue(2);
console.log(wrap1());
// → 1
console.log(wrap2());
// → 2

কেন ক্লোজার ব্যবহার করব?

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

১। আপনি যখন চাইছেন আপনার কোড Encapulated থাকুক বাইরে থেকে কোন অবাঞ্চিত পরবর্তন না হোক তখন আপনার ক্লোজার ব্যবহার করা উচিত

২। আপনি যখন চাইছেন আপনার ডাটা গ্লোবাল স্কোপ থেকে হাইড থাকুক।

৩। আপনি যখন কাস্টম কোন ইভেন্ট বা বিল্ড ইন ইভেন্ট হ্যান্ডেল করতে চাইছেন।

৪। আপনি যখন আসলে বেটার মেমোরি ম্যানজমেন্ট করতে চাইছেন তখন ক্লোজার ব্যাবহার করা উচিত।

৫। আপনার যখন কোন স্টেটে এসে মনে হবে আপনার মেমোরাইজড করা দরকার তখন ক্লোজার ব্যাবহার করতে হবে।

Last updated