
আপনি যদি কখনো জাভাস্ক্রিপ্টের লাইব্রেরী ব্যবহার করে কোন কিছু তৈরি করে থাকেন তাহলে হয়ত অবশ্যই this
কিওয়ার্ডটি লক্ষ্য করেছেন। জাভাস্ক্রিপ্টে this
খুবই একটা কমন টপিক্স। বেশ কিছু ডেভেলপার অনেক সময় ধরেই পুরোপুরি এই কনসেপ্টটাকে বোঝার চেষ্টা করেছেন যে আসলে কিভাবে this
কিওয়ার্ড কাজ করে থাকে এবং কোথায় এটা ব্যবহৃত হয়।
এই পোস্টে this
এবং এর কার্যকারিতা সম্পর্কে বিস্তারিত বোঝানোর চেষ্টা করব
তবে শুরু করার পূর্বে দেখে নিন আপনার সিস্টেমে Node ইন্সটল করা আছে কিনা? যদি না থাকে তাহলে https://nodejs.org/en/ এখান থেকে Node ইন্সটল করে নিন। তারপরে আপনার কমান্ড লাইন বা টার্মিনালে node কমান্ডটা রান করুন।
this এবং Global Environment
this এর কাজ করার সিস্টেম বোঝা মোটেও সহজ কোন কাজ নয়। this কিভাবে কাজ করে সেটা আমরা ভিন্ন ভিন্ন এনভাইরমেন্টে ব্যবহার করে দেখব। চলুন দেখে আসি this, global এনভাইরমেন্টে কিভাবে কাজ করে থাকে।
Global এনভারনমেন্ট এর ক্ষেত্রে this মানেই হচ্ছে Global অবজেক্ট।
this === global // true
// or in browser
this === window // true
কিন্তু এটি শুধু মাত্র Node Shell এর জন্যই প্রযোজ্য। আমরা ওপরের কোডটিকেই যদি একটা জাভাস্ক্রিপ্ট ফাইলে রেখে Node এনভাইরমেন্টে রান করি তাহলে আউটপুট পেতাম false।এটা পরীক্ষা করে দেখার জন্য ওপরের কোডটিকে index.js ফাইলের ভিতরে রেখে Node কমান্ড ব্যবহার করে ফাইলটা কে রান করি।
node index.js // false
এখানে false আউটপুট আসার কারণ হচ্ছে NodeJS এনভাইরমেন্টে জাভাস্ক্রিপ্ট ফাইলে this এর ভ্যালু module.export, Global না। আর এটা শুধু Node এনভাইরমেন্টের জন্যই প্রযোজ্য।
ফাংশনের ভিতরে this
একটি ফাংশনের ভিতরে this
এর ভ্যালু সাধারণত ফাংশন কল করে ডিফাইন করা হয়। (ফাংশন ইনভোক হওয়ার পূর্ব মুহুর্ত পর্যন্ত this
এর ভ্যালু অ্যাসাইন হয় না)। তাই একটি ফাংশনের ভিতরে this
এর ভ্যালু প্রত্যেকবার এক্সিকিউশনের জন্য ভিন্ন ভিন্ন হতে পারে।
পূর্বে তৈরি করা index.js ফাইলে একটি সাধারণ ফাংশন লিখুন যেটা শুধুমাত্র ফাংশনের this টা Global অবজেক্ট কিনা সেটা পরীক্ষা করে দেখবে।
function test() {
console.log(this === global);
}
test();
আমরা যদি নোড ব্যবহার করে ওপরের কোডটা রান করি তাহলে আউটপুট true
পাব। কিন্তু আমরা যদি ফাইলের ওপরে use strict
লিখে দেই তাহলে আমরা false
আউটপুট পাব। কারণ এখন this
এর ভ্যালু undefined
। বিষয়টাকে আর একটু পরিষ্কার করতে একটা নতুন ফাংশন তৈরি করা যাক, যেখানে একটি সুপার হিরোর রিয়েল নেম এবং হিরো নেমকে ডিফাইন করবে।
function Hero(heroName, realName) {
this.heroName = heroName;
this.realName = realName;
}
const superman = Hero('Superman', 'Clark Kent');
console.log(superman);
লক্ষ্য করবেন আমাদের এই ফাংশনটি কিন্তু strict mode
এ লেখা হচ্ছে না। কোডটিকে Node এ রান করলে দেখবেন এটি আশানরূপ superman এর realName ‘Superman’ এবং heroName ‘Clark Kent’ আউটপুট দিচ্ছে না। তার বদলে আউটপুট দিচ্ছে undefined
।
যেহেতু আমাদের কোডটি strict mode
এ রান করা হয়নি, সেহেতু এই this
টি Global অবজেক্ট কে রেফার করছে। যদি সেম কোডটিকে আমরা Strict mode
এ রান করি তাহলে আমরা ইরোর পাব। কারণ জাভাস্ক্রিপ্ট আমাদেরকে undefined
কোন কিছুর ভিতরে কোন প্রোপার্টি অ্যাাসাইন করতে দেয় না। এটা অবশ্য আমাদের জন্য ভাল কারণ এটা আমাদেরকে Global
ভ্যারিয়েবল ক্রিয়েট করা থেকে বিরত রাখে।
সবশেষে, ফাংশন নেম কে আপার কেসে লেখার অর্থ হচ্ছে আমাদেরকে এই ফাংশনটিকে কল করতে হলে new
অপারেটর ব্যবহার করতে হবে এবং কন্সট্রাক্টরের মত করে কল করতে হবে। ওপরের কোড স্নিপেট থেকে শেষের দুই লাইন কোড নিচের কোড দ্বারা পরিবর্ত করুন।
const superman = new Hero('Superman', 'Clark Kent'); console.log(superman);
এবং node index.js
কমান্ডটা রান করুন। আপনি আপনার প্রত্যাশিত আউটপুট পেয়ে যাবেন।
Constructor এর ভিতরে this
জাভাস্ক্রিপ্টে কোন স্পেসিয়াল কন্সট্রাক্টর ফাংশন নেই ( ES6 এর পূর্বে )। আমরা new
অপারেটর ব্যবহার করে একটা ফাংশন কল কে কন্সট্রাক্টর কলে রূপান্তর করতে পারি যা ওপরের কোডে দেখানো হয়েছে।
যখন একটি কন্সট্রাক্টর কল তৈরি হয় তখনই একটি নতুন অবজেক্ট তৈরি হয় এবং ফাংশনের this আর্গুমেন্ট হিসেবে সেট হয়ে যায়। পরে এই অবজেক্টটি ইমপ্লিসিট ভাবে ওই ফাংশন থেকে রিটার্ন হয়, যতক্ষণনা পর্যন্ত আমরা নিজে থেকে কোন অবজেক্ট রিটার্ন করি।
Hero ফাংশন এর ভিতরে নিচের কোডের মত রিটার্ন স্টেটমেন্টটি লিখুন।
function Hero(heroName, realName) {
this.heroName = heroName;
this.realName = realName;
return {
heroName: 'Batman',
realName: 'Bruce Wayne'
};
}
const superman = new Hero('Superman', 'Clark Kent'); console.log(superman);
এখন যদি আমরা node index.js
কমান্ডটা রান করি তাহলে দেখব ওপরের রিটার্ন স্টেটমেন্টটা আমাদের কন্সট্রাক্টর কলকে ওভাররাইড করে ফেলেছে। যদি রিটার্ন স্টেটমেন্টটা কোন অবজেক্টকে রিটার্ন না করে অন্য কোন কিছু রিটার্ন করে সেই ক্ষেত্রে রিটার্ন স্টেটমেন্ট কন্সট্রাক্টর কলকে ওভাররাইড করবে না। সেই ক্ষেত্রে অবজেক্টটা তার অরিজিনাল ভ্যালু বহন করবে।
Method এর ভিতরে this
যখন কোন ফাংশনকে অবজেক্টের মেথড হিসেবে কল করা হয়, তখন this
সেই অবজেক্টকে রেফার করে। তখন সেই অবজেক্টকে ফাংশন কলের রিসিভার বলা হয়।
নিচের কোডে আমার hero
অবজেক্টের মধ্যে একটা dialouge
নামের মেথড আছে। এখানে dialouge
এর this
টা hero
অবজেক্টকে রেফার করছে। তাই এখানে hero
অবজেক্টটা dialouge
মেথড কলের রিসিভার।
const hero = {
heroName: 'Batman',
dialouge() {
console.log(`I am ${this.heroName}`);
}
};
hero.dialouge();
এটা একটা খুবই সাধারণ উদাহরণ। কিন্তু রিয়েল ওয়ার্ল্ডে কাজের ক্ষেত্রে রিসিভার গুলোকে ট্রেস করা মেথডের পক্ষে খুবই কঠিন কাজ।
index.js
ফাইলের শেষের দিকে নিচের দুই লাইন কোড লেখা যাক।
const saying = hero.dialouge;
saying();
এখানে আমি dialouge
মেথডের রেফারেন্সটাকে একটি ভ্যারিয়েবল এর ভিতরে রাখছি এবং সেই ভ্যারিয়েবলটাকে ফাংশন হিসেবে কল করছি। node এ ওপরের কোডটি রান করলে দেখবেন এখানে this
undefined
রিটার্ন করছে কারণ dialouge
মেথডটি তার রিসিভার এর ট্রাক হারিয়ে ফেলেছে। এখন এই মেথডের this
টি Global কে রেফার করছে যেখানে hero
কে রেফার করার কথা ছিল।
সাধারণত রিসিভার গুলো ট্রাক হারায় যখন আমরা একটি মেথডকে অন্য কোন ফাংশনের কলব্যাক হিসেবে পাস করি। আমরা হয়ত সমস্যাটির সমাধান করতে পারি wrapper ফাংশন বা bind() মেথড ব্যবহার করে যেখানে আমরা আমাদের রিসিভার অবজেক্টকে this হিসেবে মেথডের সাথে বেধে দিতে পারি।
call()
এবং apply()
যদিও একটি ফাংশনের this এর ভ্যালু ইমপ্লিসিট ভাবেই সেট করা থাকে, তারপরেও আমরা চাইলে call()
এবং apply()
ফাংশন ব্যবহার করে বাইরে থেকে this
এর ভ্যালু সেট করে দিতে পারি। পূর্বের কোডটিকে নিচের কোডের মত পরিবর্তন করে দেখা যাক।
function dialouge() {
console.log(`I am ${this.heroName}`)
}
const hero = {
heroName: 'Batman'
}
আমাদের hero
অবজেক্টকে রিসিভার হিসেবে dialouge
ফাংশনের সাথে কানেক্ট করা দরকার। এই কাজটা করার জন্য আমরা call()
অথবা apply()
ফাংশনের সাহায্য নিতে পারি।
dialouge.call(hero)
// or
dialouge.apply(hero)
কিন্তু strict mode
এর বাইরে যদি আমরা call()
বা apply()
ফাংশন ব্যবহার করি এবং সেখানে null
বা undefined
ভ্যালু পাস করি তাহলে জাভাস্ক্রিপ্ট ইঞ্জিন এটাকে ইগ্নোর করবে। strict mode
ব্যাবহার করার এটা অন্যতম একটা কারণ।
bind()
যখন আমরা একটি মেথডকে অন্য একটা ফাংশনের কলব্যাক হিসেবে পাস করি, সেখানে সব সময় সেই মেথডের রিসিভার ডিস্ট্রাক্ট হওয়ার সম্ভবনা থাকে এবং এর this
আর্গুমেন্ট Global
অবজেক্টে পরিণত হয়ে যায়।
bind()
মেথড ব্যবহার করে একটা this
আর্গুমেন্টকে একটা পার্মানেন্ট ভ্যালু হিসেবে সেট করতে পারি। নিচের কোডের দিকে লক্ষ্য করলেই দেখা যাবে bind()
একটি নতুন dialouge
ফাংশন তৈরি করবে এবং এর this
ভ্যালুকে hero
অবজেক্ট এর ভ্যালু হিসেবে সেট করবে।
const hero = {
heroName: 'Batman',
dialouge() {
console.log(`I am ${this.heroName}`);
}
};
setTimeout(hero.dialouge.bind(hero), 1000)
এতে করে আমাদের this
এর ভ্যালুকে কখনোই call()
বা apply()
মেথড দিয়ে পরিবর্তন করা সম্ভব নয়।
Arrow ফাংশনের ভিতরে this
জাভাস্ক্রিপ্টে যেকোনো ফাংশনে this
ব্যবহার করা আর arrow
ফাংশনে this
ব্যবহার করার মধ্যে অনেক পার্থক্য রয়েছে। Arrow
ফাংশনের ভিতরে this
ব্যবহার করা হলে এটা সেই ফাংশনের ভিতরকার context কে this
এর ভ্যালু হিসেবে ধরে নেয়। যদিও this
এর একটি নিজস্ব global ভ্যালু আছে, arrow ফাংশন পার্মানেন্টলি this
এর ভ্যালুকে এমন ভাবে সেট করে, যেটাকে call()
বা apply()
মেথড দিয়েও পরবর্তীতে পরিবর্তন করা সম্ভব হয় না।
এই ক্ষেত্রে arrow ফাংশনের ভিতরে this
কিভাবে কাজ করে সেটা বোঝার জন্য নিচের কোডটি লক্ষ্য করুন।
const batman = this;
const bruce = () => {
console.log(this === batman);
};
bruce();
এখানে আমরা একটি ভ্যারিয়েবলের ভিতরে this
এর ভ্যালুকে রেখে দিলাম। তারপর একটি arrow ফাংশনের ভিতরের this
এর ভ্যালুকে বাইরের ভ্যারিয়েবলের this
এর ভ্যালু এর সাথে তুলনা করলাম। কোডটি রান করার পরে আমাদের টার্মিনালে true
আউটপুট আসার কথা। Arrow ফাংশনের ভিতরে this
এর ভ্যালুকে সরাসরি সেট করে দেওয়া যায় না। আবার যদি বাইরে থেকে call(), apply() বা bind() মেথড ব্যবহার করে this
এর ভ্যালু পাস করার চেষ্টা করা হয় তাহলে সেই ভ্যালুকে arrow ফাংশন ইগনোর করবে। অর্থাৎ arrow ফাংশনের বাইরে থেকে কোন ভাবেই this
এর ভ্যালুকে পরিবর্তন করা যায় না। যখন একটি arrow ফাংশন তৈরি হয় শুধুমাত্র তখনই this
এর ভ্যালু সেট হয়ে যায়।
Arrow ফাংশনকে কখনোই কন্সট্রাক্টর হিসেবে ব্যবহার করা যায় না। যেহেতু arrow ফাংশনের this
এ কোন প্রোপার্টি যুক্ত করা যায় না, তাহলে arrow ফাংশনের এই this
ঠিক কি কাজে লাগে?
Arrow ফাংশন আমাদেরকে একটি কলব্যাক ফাংশনের this
কে এক্সেস করতে সাহায্য করে। এটি কিভাবে করে জানতে নিচের কাউন্টার অবজেক্ট এর দিকে লক্ষ্য করুন -
const counter = {
count: 0,
increase() {
setInterval(function () {
console.log(++this.count);
}, 1000);
}
};
counter.increase();
এই কোডটিকে রান করলে এটা আমাদেরকে শুধুমাত্র NaN
এর একটি লম্বা লিস্ট দিবে। কারণ এখানে this.count
সরাসরি counter
অবজেক্টকে রেফার করছে না। এটা আসলে রেফার করছে Global অবজেক্টকে। এই counter
টিকে সঠিক ভাবে কাজ করাতে হলে কোডটিকে arrow ফাংশন ব্যবহার করে সাজাতে হবে।
const counter = {
count: 0,
increase() {
setInterval(() => {
console.log(++this.count);
}, 1000);
}
};
counter.increase();
আমাদের কলব্যাক ফাংশনটি এখন increase
মেথড এর সাথে bind করা this
কে ব্যবহার করছে এবং এখন কিন্তু counter
যেমনটি কাজ করার কথা ছিল ঠিক তেমনই করছে।
নোটঃ ++this.count
এর পরিবর্তে this.count + 1
লিখলে কাজ করবে না। কারণ এখানে counter
টা শুধুমাত্র এর ভ্যালুকে এক করে বৃদ্ধি করবে এবং প্রত্যেকবার একটি করে নতুন ভ্যালু রিটার্ন করবে।
Class এর ভিতরে this
যেকোনো জাভাস্ক্রিপ্ট অ্যাপ্লিকেশনে class হচ্ছে সব থেকে গুরুত্বপূর্ণ একটি অংশ। চলুন দেখা যাক this
কিভাবে class
এর ভিতরে কাজ করে।
সাধারণত যে কোন class
এর একটি কন্সট্রাক্টর থাকে যেখানে this
যেকোনো নতুন অবজেক্টকে রেফার করে। কিন্তু মেথডের ক্ষেত্রে this
অন্য ভ্যালুও রেফার করতে পারে। যদি সেই মেথডকে কোন সাধারণ ফাংশনের মত কল করা হয় এবং একই ভাবে মেথডের মত class
ও কিন্তু তার রিসিভার অবজেক্টের ট্রাক হারাতে পারে।
চলুন Hero
নামের নতুন একটি class
তৈরি করি যা আগে আমরা ফাংশন আকারে দেখেছিলাম। এই class
এ থাকবে একটি কন্সট্রাক্টর এবং dialouge
মেথড। সব শেষে আমরা class
এর একটি ইন্সট্যান্স তৈরি করে dialouge
মেথডকে কল করব।
class Hero {
constructor(heroName) {
this.heroName = heroName;
}
dialouge() {
console.log(`I am ${this.heroName}`);
}
}
const batman = new Hero('Batman');
batman.dialouge();
এখানে কন্সট্রাক্টরের ভিতরের this
, class
এর একটি নতুন ইন্সট্যান্সকে রেফার করছে। যখনই আমরা batman.dialouge()
মেথডকে কল করছি, তখনই আমরা dialouge
কে মেথড হিসেবে এবং batman
কে এর রিসিভার হিসেবে ব্যবহার করছি। কিন্তু আমরা যদি dialouge
মেথডের রেফারেন্সটা কোথাও স্টোর করে রাখি এবং পরে সেটাকে ফাংশন হিসেবে কল করি তাহলে আমরা আবারো মেথডের রিসিভার হারাবো। তার সাথে এটি this
কেও `undefined` রেফার করবে।
const say = batman.dialouge;
say();
এই ইরোর এর কারণ হল জাভাস্ক্রিপ্টে class
গুলো ইমপ্লিসিট ভাবেই strict mode
এ থাকে। আমরা say()
ফাংশনকে কল করছি কোন অটোবাইন্ডিং ছাড়াই। এই সমস্যাটাকে সমাধান করতে হলে আমাদেরকে dialouge
ফাংশনকে বাইরে থেকে batman
এর সাথে বাইন্ড করে দিতে হবে। আমরা এই bind()
টা class
এর কন্সট্রাক্টরের ভিতরেও করতে পারতাম।
const say = batman.dialouge.bind(batman);
say();
পরিশেষে
জাভাস্কিপ্টে this keyword কে অনেকটা ইংলিশ এর pronoun এর মত করে ব্যবহার করতে হবে। যেমন -
- Shegufa Taranjum loves DC Comics
- Shegufa Taranjum also loves Marvel Movies
এই দুইটা বাক্যকে একসাথে বলতে গেলে আমরা বলবো, Shegufa loves DC Comics and she also loves Marvel Movies। এই ছোট্ট একটা গ্রামার থেকে আমরা জাভাস্ক্রিপ্টে this এর গুরুত্বটা বুঝতে পারছি। এখানে she দুইটা বাক্যকে যুক্ত করছে। ঠিক একই ভাবে জাভাস্ক্রিপ্টে this ও একটি শর্টকাট রেফারেন্স হিসেবে কাজ করে থাকে।
আশা করি এই পোস্টটি আপনাদের অনেক সাহায্য করবে এবং this
নিয়ে যত কনফিউশন ছিল দূর করবে। এখন আপনি জানেন কিভাবে, কেন এবং কোথায় এই গুরুত্বপূর্ণ this keyword টি ব্যবহার করতে হবে।
আর তারপরেও যদি বুঝতে সমস্যা হয় তাহলে Stack Learner ইউটিউব চ্যানেল থেকে this এবং অবজেক্ট অরিয়েন্টেড জাভাস্কিপ্টের পূর্নাঙ্গ প্লেলিস্ট দেখে নিতে পারেন। নিচে রেফারেন্সে লিংক দেওয়া রইল।
বিশেষ দ্রষ্টব্যঃ এটি একটি অনুবাদকৃত আর্টিকেল। এই আর্টিকেলটি অনুবাদ করা হয়েছে Rajat S এর What is “this” in JavaScript? আর্টিকেলটি থেকে।

