this-কে bind দিয়া call কর
যখন ক্লাসের বেশির ভাগ পোলাপান পরীক্ষা বা ক্লাস টেস্ট পিছাতে চায়, তখন দেখা যায় ক্লাসের সবাই রাজি, শুধু একজন আঁতেল বেঁকে বসে। সে চায় পরীক্ষা অনটাইমেই হবে। তখন ক্লাসের সবাই তাকে ধরে বেঁধে পারলে কোলে তুলে স্যারের রুমে নিয়ে যায়— পরীক্ষা পেছানোর রিকোয়েস্ট করার জন্য। জাভাস্ক্রিপ্টে দরকার হলে this-কে ধরে বেঁধে নিয়ে আসা যায়।
জাভাস্ক্রিপ্টে this বলতে বুঝায় কোন কনটেক্সটে ফাংশন রান করবে বা মেথড রান করবে বা কোন জিনিসের ওপরে রান করবে।
একটা জিনিস আমরা সিম্পলভাবে জানি। অবজেক্টের ভিতরে কোনো মেথড বা ফাংশনের ভিতরে যদি this থাকে, তাহলে সেই this বলতে সেই ফাংশনকে বুঝায়।
এইবার সিম্পল একটা অবজেক্ট দেখি যেটার মধ্যে নাম, স্যালারি আর getInfo নামের মেথড আছে। getInfo মেথডের মধ্যে this অবজেক্ট থেকে নাম আর স্যালারি নিয়ে কনসোল লগ করতেছে। এখন আমি যদি getInfo মেথডকে কল করি, তাহলে সে স্বাভাবিকভাবেই tina অবজেক্ট থেকে ইনফো দেখাবে। নিচের মতো করে—
const tina = {
name: "Tina",
salary: 20000,
getInfo() {
console.log(`${this.name} salary: ${this.salary}`);
}
};
tina.getInfo()
Output: Tina salary: 20000এরপর আমার কাছে আরেকটা অবজেক্ট আছে, যেটার নাম soma।
const soma = {
name: 'Soma',
salary: 15000
}ওপরে আরেকবার খেয়াল করে আয়, getInfo-এর মধ্যে কিন্তু আমরা this ইউজ করে this.name দিয়ে অবজেক্টের নাম নিচ্ছি। আবার একইভাবে this.salary দিয়ে অবজেক্টের স্যালারি নিচ্ছি। ভালো কথা।
এখন কাজ হচ্ছে, আমরা tina-এর getInfo মেথডটা soma-এর সাথে বেঁধে দিব।
.bind()
soma অবজেক্টের মধ্যে যদি tina-এর getInfo মেথড ইউজ করতে যাস, তাহলে this-এর মান হিসেবে tina-কে ইউজ না করে বরং soma-কে বাইন্ধা দিতে হবে। আর এই বাইন্দা দেয়ার কাজ করব আমরা bind দিয়ে। নিচের মতো করে একটা ফাংশন ডিক্লেয়ার কর। যেটার নাম দিবি somaInfo বা তুই চাইলে অন্য কোনো নামও দিতে পারস। আর ডানপাশে tina.getInfo লেখার পর ডট চিহ্ন দিয়ে bind লিখে ফেলবি।
তারপর bind-এর ভিতর প্রথম প্যারামিটার হিসেবে soma অবজেক্ট দিয়ে দিবি। তাহলে কী হবে? তাহলে এই getInfo ইউজ করার সময় সে this হিসেবে soma-কে যেহেতু বাইন্ধা দেয়া হইছে, তাই soma-কে this হিসেবে ইউজ করবে।
বিশ্বাস না হলে somaInfo ফাংশনকে কল করে দেখ।
const somaInfo = tina.getInfo.bind(soma);
somaInfo()
Output: Soma salary: 15000কাহিনি বুঝছস। সেই একই getInfo মেথড এবং একই tina-এর মেথড কিন্তু তুই জোর করে soma-কে this হিসেবে বাইন্ধা দিতে পারছিস।
এইটা দিয়ে বুঝা যায়। তুই চাইলে তোর ইচ্ছামতো অবজেক্ট দিয়ে যেকোনো ফাংশন বা মেথডের this ভ্যালু সেট করতে পারবি।
অর্থাৎ .bind() হলো এমন একটা মেথড, যা ফাংশনকে permanently কোনো নির্দিষ্ট অবজেক্টের সাথে বেঁধে ফেলে। মানে, যখনই ফাংশনটা কল হবে, এটা ওই ফাংশনের context (মানে this)-এর মান জোর করে সেট করে দিবে।
.call
bind তো আমরা বাইন্ড করে একটা ফাংশনে রাখছি। তারপর কল করছি। এইটার ডাইরেক্ট ভার্সন হচ্ছে call ফাংশন। কল করার সময় মেথডের নামের পর ডট চিহ্ন দিয়ে তারপর call লিখে ব্র্যাকেটের মধ্যে কোনো একটা অবজেক্ট দিয়ে দিবি। তাহলে সেই অবজেক্টটাই হবে ঐ ফাংশনের ভিতরে this-এর মান।
নিচে mona নামে একটা অবজেক্ট আছে। তারপর সেই tina-এর getInfo লিখে ডট চিহ্ন দিয়ে call লিখে সেটার ভিতরে mona অবজেক্ট দিয়ে দিছি। তাহলে দেখ সে mona-এর ইনফো আউটপুট হিসেবে দিছে।
const mona = {
name: 'Mona',
salary: 25000
}
tina.getInfo.call(mona);
Output: Mona salary: 25000দেখছিস, কী ম্যাজিক। tina-এর getInfo-এর ভিতরের this-এর মান কত সহজেই চেইঞ্জ করে দিসি।
.apply()
.apply() অনেকটা .call()-এর মতোই হালকা একটু ডিফারেন্স আছে। তবে বেসিক অংশ কিন্তু একই। জাস্ট ওপরের call-এর মতো করে apply করে দিবি। নিচে dina নাম একটা অবজেক্ট আছে। তার নিজস্ব কোনো getInfo মেথড নাই। তাই tina-এর getInfo method-এর ডট চিহ্ন দিয়ে apply লিখে ব্র্যাকেটের ভিতরে dina লিখে দিছি। যাতে tina-এর getInfo মেথড ইউজ করার সময় যত জায়গায় this ইউজ করা হইছে, সব জায়গায় this হিসেবে dina-কে ইউজ করে।
const dina = {
name: 'Dina',
salary: 35000
}
tina.getInfo.apply(dina);
Output: Dina salary: 35000তুই দেখছস, কত সহজেই this-কে তুই পাল্টায় ফেলতে পারস।
bind call apply এর প্যারামিটার
ওপরে আমরা যখন getInfo মেথড লিখছিলাম, সেটার কোনো প্যারামিটার ছিল না। যদি প্যারামিটার থাকতো, তাহলে bind-এর ক্ষেত্রে প্রথম প্যারামিটার হিসেবে this-এর মান, তারপর বাকি প্যারামিটারগুলো কমা দিয়ে দিয়ে আলাদা করে দিতাম। সেইম সিস্টেমে call-এর ক্ষেত্রেও প্রথম প্যারামিটার হতো this, আর তারপরের প্যারামিটারগুলা কমা দিয়ে দিয়ে আলাদা করে দিতাম। অন্যদিকে apply-এর ক্ষেত্রে প্রথম প্যারামিটার this, আর বাকি প্যারামিটারগুলো একটা array-এর মধ্যে নিয়ে array হিসেবে পাস করা লাগে।
এই bind call apply-এর ডিফারেন্সের চাইতে ইম্পরট্যান্ট জিনিস হচ্ছে, তুই চাইলে যেকোনো ফাংশনের this-এর মান ইচ্ছামতো সেট করে দিতে পারস। সেটাই তোর একটা সুপার পাওয়ার।
Practice:
- টিম নামে একটা অবজেক্ট বানা, যার মধ্যে name এবং players থাকবে। players-এর মধ্যে খেলোয়াড়ের সংখ্যা থাকবে। এ ছাড়া টিমের মধ্যে একটা মেথড থাকবে play নামে, যেখানে this.name এবং this.players দিয়ে একটা স্ট্রিং বানিয়ে কনসোল লগ করবি। প্রথমে team থেকে play মেথডকে কল করে আউটপুট দেখ। তারপর আরেকটা অবজেক্ট বানা tournament নামে। সেটার মধ্যেও name এবং players থাকবে। টুর্নামেন্টে কতজন খেলোয়াড় খেলতেছে, সেই সংখ্যা থাকবে। এখন .bind() ইউজ করে team অবজেক্টের play মেথড ইউজ করবি, তবে সেটার this হিসেবে টুর্নামেন্টকে ইউজ করবি।
- একটা car অবজেক্ট বানা, যার মধ্যে speed এবং price থাকবে। এরপর একটি মেথড drive বানা, যেখানে this.speed এবং this.price দিয়ে গাড়ির তথ্য কনসোল লগ করবে। এখন car অবজেক্টের drive ইউজ করবি .call() ব্যবহার করে। তবে this-এর মান হিসেবে একবার bike নামের একটা অবজেক্ট দিয়ে দিবি। আবার truck নামের আরেকটা অবজেক্ট দিয়ে দিবি। আর bike এবং truck এই দুই অবজেক্টই speed আর price প্রোপার্টি থাকবে।
- একটা অবজেক্ট বানা "employee" নামে, যার মধ্যে name এবং role থাকবে। employee-এর মধ্যে একটা মেথড থাকবে "details" নামে, যেখানে this.name এবং this.role দিয়ে কনসোল লগ করবে। প্রথমে employee থেকে details মেথড কল করে আউটপুট দেখ। এরপর আরেকটা অবজেক্ট বানা "manager" নামে, যার মধ্যে name এবং role থাকবে। এখন .apply() ব্যবহার করে employee-এর details মেথড manager ইউজ কর।
- একটা অবজেক্ট বানা "classroom" নামে, যার মধ্যে name এবং students থাকবে। students-এর মধ্যে অনেকগুলা student-এর নাম থাকবে। classroom-এর মধ্যে একটা মেথড থাকবে "attendance" নামে, যেখানে this.name এবং this.students-এর নামগুলো কমা দিয়ে join করে স্ট্রিং বানিয়ে কনসোল লগ করবে। প্রথমে classroom থেকে attendance মেথড কল করে আউটপুট দেখ। এরপর অন্য একটা অবজেক্ট বানা "lab" নামে, যার মধ্যে name এবং students থাকবে। এবার .bind() ব্যবহার করে classroom-এর attendance মেথড lab-এর সাথে বেঁধে দে।