মোস্ট কনফিউজিং this
নতুন নতুন প্রেমে পড়লে পোলাপান শয়নে-স্বপনে-জাগরণে তাকে দেখতে পায়। একই অবস্থা হয় কিছুদিন জাভাস্ক্রিপ্ট ইউজ করার পর। একদম শয়নে-স্বপনে-জাগরণে এমনকি আগানে-বাগানে-চিপাচাপায়— সব জায়গায় this কি-ওয়ার্ড দেখতে পায়।
শুধু দেখলে সমস্যা ছিল না। দেখতে গিয়ে একেক জায়গায় তার একেক রূপ, একেক মোহ আর একেক আচরণ দেখে পোলাপান ফিদা হওয়ার পাশাপাশি কনফিউজডও হতে শুরু করে। this আসলে কী জিনিস?
this একটা ইংরেজি শব্দ। যার মানে হচ্ছে এই, এটা ইত্যাদি। আরেকটু স্পেসিফিকভাবে বললে বলা যায়— this বলতে বুঝায় ‘এটার’ বা এই অবজেক্টের।
this হলো জাভাস্ক্রিপ্টের একটা বিশেষ কি-ওয়ার্ড, যেটা একেক সময় একেক ধরনের অবজেক্টকে রেফার করে। কারণ, this-এর ভ্যালু ডিপেন্ড করে কোথায় এবং কীভাবে— এটা ব্যবহার করা হচ্ছে তার ওপর। তাই বিভিন্ন কনটেক্সটে this-এর বিহেভিয়ারের কয়েকটা উদাহরণ দেখে ফেলি।
1. Global Context (বা window object)
তুই যদি ব্রাউজারে গিয়ে this-কে কনসোল লগ করিস, তাহলে তোকে window অবজেক্ট দেখাবে। এইটা হচ্ছে ব্রাউজারে জাভাস্ক্রিপ্টের সব জিনিস ধরে রাখে। একদম মেইন জিনিস দেখাবে।
console.log(this);
Output:
Window {0: global, window: Window, document: document, …}এইটাকে ক্ষেত্রবিশেষে window, this, global this এইসব নামে ডাকে। গ্লোবাল অবজেক্ট হলো এমন একটা অবজেক্ট, যেটা সব গ্লোবাল ভেরিয়েবল, ফাংশন এবং প্রোপার্টিগুলোকে ধরে রাখে। ওভারঅল জাভাস্ক্রিপ্ট কীভাবে চলবে, সেটা ঠিক করে এবং যেখানেই জাভাস্ক্রিপ্ট চলুক না কেন, সেখানেই একটা গ্লোবাল অবজেক্ট থাকবেই। এইটাই মেইন জিনিস।
2. অবজেক্টের মেথডের মধ্যে
যখন "this" অবজেক্টের মধ্যে কোনো মেথড ব্যবহার করা হয়, তখন এটা সেই অবজেক্টকেই নির্দেশ করে। ধর, নিচের মতো অবজেক্ট আছে—
const player = {
name: 'Sakep',
score: 100,
showScore() {
console.log(this);
}
};
player.showScore();
Output: {name: 'Sakep', score: 100, showScore: ƒ}showScore মেথডের মধ্যে "this" বলতে player অবজেক্টকে বুঝায়। কারণ, মেথডটা অবজেক্টের মধ্যেই আছে।
যেহেতু this বলতে সেই অবজেক্টকে বুঝায়, তাই আমরা সেই অবজেক্টের মধ্যে যদি কোনো প্রোপার্টি বা মেথডকে এক্সেস করতে চাই, তখন আমরা this অবজেক্টের ওপরে সেই অবজেক্টের প্রোপার্টি বা মেথডকে এক্সেস করি। যেমন, আমি যদি showScore-এর ভিতরে name বা score এক্সেস করতে চাই, তাহলে this-এর পর ডট চিহ্ন দিয়ে তারপর সেই প্রোপার্টির নাম লিখব। নিচের মতো করে—
const player = {
name: 'Sakep',
score: 100,
showScore() {
console.log(this.score);
}
};
player.showScore();
Output: 100player অবজেক্টের যেকোনো মেথডের ভিতরে "this.name" মানে player অবজেক্টের name প্রোপার্টির মান। একইভাবে মানে "this.score" মানে player অবজেক্টের score প্রোপার্টির মান।
3. class-এর মধ্যে
ES6-এর class-এর ভিতরে যখন আমরা this ইউজ করি, সেটা সেই ক্লাসকে না; বরং সেই ক্লাস থেকে যেসব অবজেক্ট তৈরি হবে, তাদেরকে বুঝায়। সেজন্য কোনো ক্লাসের মধ্যে this.name বলতে বুঝায় সেই ক্লাস থেকে যেসব অবজেক্ট তৈরি হবে, তাদের name প্রোপার্টিকে বুঝায় [জিনিসটা অবজেক্টের ভিতরে this-এর মতোই বলতে পারিস। তবে টেকনিক্যালি বললে হালকা একটু ডিফারেন্স আছে। ]
নিচে আমরা প্লেয়ার ক্লাস লিখছি, তারপর সেটা থেকে gamer অবজেক্ট বানাইছি। পরে যখন gamer.showDetails-কে কল করছি, তখন সেই মেথডের ভিতরে this বলতে gamer অবজেক্টকে বুঝায়।
class Player {
constructor(name, level) {
this.name = name;
this.level = level;
}
showDetails() {
console.log(this.name);
console.log(this.level);
}
}
const gamer = new Player('Alex', 5);
gamer.showDetails();
Output:
Alex
54. Normal function
নরমাল একটা ফাংশনের মধ্যেও কিন্তু this ইউজ করা যায়। তবে সেটা ডাইরেক্ট window বা মেইন অবজেক্টকে বুঝাবে।
function doSomething(number) {
console.log(this);
}
doSomething();
Output:
Window {0: global, window: Window, document: document, …}5. Constructor Function-এর মধ্যে
মূলত ES6 আসার আগে class কি-ওয়ার্ড দিয়ে ক্লাস বানানো যেত না। তখন ফাংশন দিয়ে ক্লাস বানানো হতো। সেক্ষেত্রে ফাংশন একটা constructor হিসেবে কাজ করত। সেজন্য ফাংশনকে কনস্ট্রাক্টর হিসেবে ইউজ করলে ফাংশনের মধ্যে "this" নতুন তৈরি হওয়া অবজেক্টকেই নির্দেশ করে।
function Person(name) {
this.name = name;
}
const user = new Person('Ayan');
console.log(user.name);
Output: Ayanএই Person ফাংশনকে কল করার সময় যদি তার নামের আগে new দিয়ে ফেলে, তাহলে সে নতুন একটা অবজেক্ট তৈরি করবে। সেক্ষেত্রে this বলতে গ্লোবাল বুঝাবে না; বরং বুঝাবে নতুন তৈরি হওয়া অবজেক্টকে। তাই this.name মানে ওই নতুন অবজেক্টের name প্রোপার্টিকে বুঝাবে।
যদিও ES6 আসার পর আর কেউ এইভাবে ক্লাস বানায় না। যদিও ES6 এসে আগের অনেক কিছুকে নতুনভাবে লেখার সিস্টেম নিয়ে আসছে, তাই কেউ কেউ ES6-এর ক্লাসকে syntactical sugar বলে। যদিও এইটা পুরাপুরি সত্যি না। কারণ, ES6-এর পরে ক্লাসের ভিতরে ভিতরেও কিছু চেইঞ্জ আসছে। বিশেষ করে ক্লাসের ওপরে এডভান্সড অনেক ফিচার আসছে, যেগুলা ES6-এর আগে করাই যেত না বা পুরাপুরি ডিফারেন্টভাবে করা হতো।
6. Event Listener-এর মধ্যে
ইভেন্ট হ্যান্ডলার বা লিসেনারে "this" সেই ইলিমেন্টকে নির্দেশ করে, যেটাতে ইভেন্ট ঘটছে।
<button id="get-user"> element that was clicked</button>
document.getElementById("get-user").addEventListener("click", function() {
console.log(this);
});
Output: <button id="get-user"> element that was clicked</button> এইখানে this বলতে সেই এলিমেন্ট বুঝায়। ওপরে আমরা যেহেতু একটা বাটনের ওপরে ক্লিক করেছি, তাই সে সেই বাটনকে this বানায় ফেলছে। যদি আমরা অন্য কিছুর উত্তরে ক্লিক বা অন্য কোনো ইভেন্ট ট্রিগার করতাম, তাহলে ইভেন্ট হ্যান্ডলারের ভিতরে this বলতে সেই এলিমেন্টকে বুঝাত।
7. Object মেথড arrow ফাংশন
অবজেক্টের মধ্যে মেথড ( ফাংশন) দুইভাবে ডিক্লেয়ার করা যায়। এক হচ্ছে নরমাল ফাংশন দিয়ে, আরেকটা হচ্ছে অ্যারো ফাংশন দিয়ে।
অবজেক্টের মধ্যে মেথড হিসেবে অ্যারো ফাংশন ডিক্লেয়ার করলে সেটার ভিতরে this আর নরমাল ফাংশনের ভিতরের this কিন্তু সেইম না। তাই অ্যারো ফাংশনে this দিয়ে যেই অবজেক্টের মধ্যে মেথড লিখছিস, সেটাকে বুঝাবে না।
অ্যারো ফাংশনে this হলো আউটার স্কোপের this। এখানে আউটার স্কোপ হলো গ্লোবাল স্কোপ (window বা global)। আর name প্রোপার্টি আছে person-এর মধ্যে, তার আউটার স্কোপ বা গ্লোবাল স্কোপে name প্রোপার্টি নেই, তাই this.name হলো undefined।
const person = {
name: "John",
greet: () => {
return `Hello, I am ${this.name}`;
}
};
console.log(person.greet());
Output: Hello, I am undefinedমেথড অ্যারো ফাংশন দিয়ে ডিক্লেয়ার করলে this এর ভ্যালু লেক্সিকাল স্কোপিং ফলো করে। এবং এইটা সেই অবজেক্ট কে বুঝে আউটার স্কোপকে বুঝায়।
7. "use strict" মোডে
যদিও স্ট্রিক্ট মোড নিয়ে এখনও আলোচনা করিনি। একটু পরে করব, তারপরেও জেনে রাখ— যদি "use strict" মোডে কাজ করিস, আর গ্লোবাল স্কোপে বা ফাংশনের বাইরে this ব্যবহার করিস, তাহলে এটা undefined হয়ে যাবে। কারণ, "strict mode"-এ this-কে window হিসেবে ধরে না।
"use strict";
function test() {
console.log(this);
}
test();
Output: undefinedফাইনাল কথা হচ্ছে, এত কিছু দেখে তোর মাথা আউলায় যেতে পারে। কেন this এত এত আলাদা জিনিস বুঝায়।
কোথায় কল করতেছস
this-এর মান
Global Context
Window বা global this
use strict-সহ গ্লোবাল কনটেক্সট
undefined
Object-এর মেথড
সেই অবজেক্ট
Constructor Function
নতুন তৈরি হওয়া অবজেক্ট
class
নতুন তৈরি হওয়া অবজেক্ট
Event Listener
যে ইলিমেন্টে এ ইভেন্ট ঘটছে
Object মেথড Arrow function
Window বা global this
this আলাদা আলাদা পরিস্থিতিতে আলাদা জিনিসকে নির্দেশ করলেও জিনিসটা আসলে ওতো কঠিন না; বরং পানির মতো সোজা। সেটা একটু পরে খুব সহজভাবে বলতেছি।
Practice:
- ব্রাউজারে window অবজেক্ট জিনিসটা কী?
- ব্রাউজারে console.log(this); রান করলে this-এর ভ্যালু কী হবে?
- অবজেক্টের মেথড নরমাল ফাংশন আর arrow ফাংশন দিয়ে ডিক্লেয়ার করলে this-এর কোনো কিছু কি ডিফারেন্ট হবে?