JavaScript 'this' keyword article in Bangla - .call(), .apply() and .bind()

মনে করুন আপনার অনেক গুলো বাড়ি আছে, এখন আপনি একজন বাড়ি রঙ করে এইরকম লোক কে সাথে নিয়ে আপনার একটা বাড়ি তে আছেন এবং তাকে বলতেছেন যে এই বাড়ি টি রঙ করতে হবে। আপনি কিন্তু বলছেন না যে এই রোড অমুক জায়গার বাড়িটি রঙ করতে হবে। অর্থাৎ আপনি এখন যেখানে আছে তাকে বোঝানোর জন্য আমরা এই শব্দটি ব্যবহার করতে পারি। ইংরেজিতে আমরা যাকে this বলতে পারি। আর যে রঙ করবে সেই কিন্তু বুঝে যাবে এই দিয়ে এখন যেখানে আছে সেই বাড়িকেই বোঝানো হয়েছে।

জাভাস্ক্রিপ্ট এ this এভাবেই কাজ করে থাকে। এই this বিভিন্ন কাজে ফাংশন কে রিইউজেবল করতে হেল্প করে থাকে।

জাভাস্ক্রিপ্ট এ this চারটি রুল অনুযায়ী চলে। এই চারটি রুল বুঝে ফেললে কোন this কোথায় কাকে কোন অব্জেক্ট কে পয়েন্ট করছে তা আর বুঝতে সমস্যা হবে না।

  • implicit binding
  • explicit binding
  • new binding
  • window binding

implicit binding

চলুন একটা সিম্পল অব্জেক্ট লিখি।

const sakib = { name: 'Shakib', age: 35, printName: function () { console.log(this.name); }, }; sakib.printName();

উপরের কোডে যে this ব্যবহার করা হয়েছে এখানে এই this কাকে পয়েন্ট করবে কারন এখানে যদি আমাদের অই উপরের বাস্তবিক উদাহরণ টা নিয়ে আসি তাহলে ত এই ফাংশন এর ভিতর এর দুনিয়া কে বোঝানো হচ্ছে নাকি সাকিব অব্জেক্ট কে বোঝানো হচ্ছে। জাভাস্ক্রিপ্ট ত মানুষের মতো বুঝে নিবে না। এটা বুঝার জন্য আমাদের দেখতে হবে কাকে কল করা হচ্ছে এখানে printName() কে প্রথমে এই ফাংশন বডির কাছে যেতে হবে। তারপর দেখতে হবে এই printName() এর পূর্বে কোনো . দিয়ে কোনো অব্জেক্ট আছে কি না যদি থাকে তাহলে এই printName() ফাংশন এ ব্যবহার করা this হচ্ছে . এর পূর্বে ইমিডিয়েটলি এই sakib অব্জেক্ট এর।

কিন্তু এই নিয়ম অ্যারো ()=> ফাংশন এর ক্ষেত্রে প্রযোজ্য নয়।

কিন্তু যদি এমন হয় যে sakib অব্জেক্ট এ name নামে কোনো প্রোপার্টি না থাকে তাহলে window.object এর মতো কাজ করবে।

চলুন আরেকটি ওয়েতে দেখা যাকঃ-

function printNameFunction(obj) { obj.printName = function () { console.log(`${this.name}`); }; } const sakib = { name: 'Sakib', age: 35, }; const tamim = { name: 'Tamim', age: 32, }; printNameFunction(sakib); printNameFunction(tamim); sakib.printName(); //output - Sakib tamim.printName(); //output - Tamim

এখানেও implecit binding রুল কাজ করছে। আমার কল করছি printName() ফাংশনকে, তার পূর্বে . দিয়ে কিছু একটা অব্জেক্ট আছে। এই ক্ষেত্রে printName() ফাংশন এর this হবে . এর পূর্বে ইমিডিয়েটলি অব্জেক্টটি।

var Person = function (name, age) { return { name: name, age: age, printName: function () { console.log(this.name); }, fatherName: { name: 'Mr. Ali', printName: function () { console.log(this.name); }, }, }; }; const sakib = Person('Sakib', 35); sakib.printName(); //output - Sakib sakib.fatherName.printName(); //output - Mr. Ali

দেখুন এখানে কিন্তু একটু ব্যতিক্রম আছে প্রথমে যখন sakib.printName(); কল করা হয় তখন তার ইমিডিয়েট অব্জেক্ট হচ্ছে সাকিব অব্জেক্ট তাই const sakib = Person('Sakib', 35); এর name আউটপুট হবে।
কিন্তু যখন sakib.fatherName.printName(); একে কল করা হয় তখন কিন্তু আমাদের কল করা ফাংশন এর ইমিডিয়েট অব্জেক্ট হচ্ছে fatherName তাই এটা হবে this, তাই আউটপুট আসছে Mr. Ali। যদি আপনার fatherName অব্জেক্ট এ name প্রোপার্টি না থাকে তাহলে সিম্পল undefined আসবে। এটাই হচ্ছে implecit binding

explicit binding

explicit binding এ তিনটি মেথড কাজ করে থাকে।

  • call()
  • apply()
  • bind()
var printName = function () { console.log(this.name); }; var sakib = { name: 'Sakib', age: 35, }; printName.call(sakib);

এখানে দেখুন printName() ফাংশন অন্য কন্টেক্সে গ্লোবাল এ আছে তাহলে এই ফাংশন এ ব্যবহার করা this কে আমার স্পট ভাবে বলে দিতে পারি এটাকেই বলা হচ্ছে implicit binding এটা কে করার জন্য ফাংশন কে call() দিলে ইনবোক করে দিতে পারি এবং প্যারামিটার হিসেবে যেই অব্জেক্টকে this করতে চাচ্ছি তাকে আমরা দিয়ে দিতে পারি। printName.call(sakib);

এখন যদি printName ফাংশন এর প্যারামিটার দরকার হয় তখন কিভাবে দিবো, এটি করার জন্য call() এর সেকেন্ড প্যারামিটার যত ইচ্ছে তত ভ্যালু পাঠাতে পারি যাকে আমরা printName ফাংশন এ ব্যবহার করতে পারবো।

var printName = function (v1, v2, v3) { console.log(`${this.name} ${v1}, ${v2}, ${v3}`); }; var sakib = { name: 'Sakib', age: 35, }; printName.call(sakib, 'Handsome', 'All-rounder', 'Best Player'); //output - Sakib Handsome, All-rounder, Best Player

এখন call() এর সেকেন্ড প্যারামিটার এ দেওয়া সকল ডাটা গুলো যদি একটা অ্যারে হতো তাহলে কি call() ব্যবহার করতে পারতাম - না। কারন call() অ্যারে নেয় না। সমধান হলো call() এর মতো explicit ভাবে this কে বলে দেয় এবং সেকেন্ড প্যারামিটার এ অ্যারে নেয় এমন মেথড হলো apply()

var printName = function (v1, v2, v3) { console.log(`${this.name} ${v1}, ${v2}, ${v3}`); console.log(v); }; var sakib = { name: 'Sakib', age: 35, }; const v = ['Handsome', 'All-rounder', 'Best player']; printName.apply(sakib, v); //output - Sakib Handsome, All-rounder, Best Player

আরেকটি কন্সেপ্ট হলো bind() এটি ও call() এর মতো কাজ করে কিন্তু পার্থক্য হলো call() কে যে ফাংশন এর সাথে ব্যবহার করা হয় তাকে কল করে দেয়। আর bind() ফাংশন কে কল করে না ফাংশন বডি কে রিটার্ন করে দেয়। তাই bind() ব্যবহার করলে তাকে আগে একটি ভেরিয়েবল এ স্টোর করতে হবে। তারপর তাকে কল করে দিতে হবে। এই হলো call() and bind() এর মধ্যে পার্থক্য।

var printName = function (v1, v2, v3) { console.log(`${this.name} ${v1}, ${v2}, ${v3}`); console.log(v); }; var sakib = { name: 'Sakib', age: 35, }; const newFunc = printName.bind(sakib, 'Handsome', 'All-rounder', 'Best player'); newFunc(); //output -Sakib Handsome, All-rounder, Best Player

new binding

যারা আমার লেখা প্রোটোটাইপ এর আর্টিকেলটি পরেছেন তাদের এর new binding বুঝতে সুবিধা হবে। সেখানে দেখানো হয়েছিলো কিভাবে ফাংশন কন্সট্রাক্টর মাধ্যমে অব্জেক্ট তৈরি করা যায়। চলুন কন্সট্রাক্টর অব্জেক্ট বানাই-

function Person(name, age) { this.name = name; this.age = age; consolo.log(`${this.name} is ${this.age} years old`); } const sakib = new Person('Sakib', 35);

তখন বলেছিলাম এভাবে new দিয়ে অব্জেক্ট বানানো হলে ২টি লাইন লিখতে হয় না বোঝানোর জন্য নিচে লেখা হলোঃ

function Person(name, age) { // let this = Object.create(null) this.name = name; this.age = age; consolo.log(`${this.name} is ${this.age} years old`); // return this } const sakib = new Person('Sakib', 35);

অর্থাৎ কন্সট্রাক্টর ফাংশন এ this নামেই একটি অব্জেক্ট বানাই পরে এই অব্জেক্টেই রিটার্ন করে দেয়। এবং new এই this কেই পয়েন্ট করে।

window binding

চলুন প্রথমে একটি ইউসকেস বানাই।

var printName = function () { console.log(this.name); //output - undefined }; var sakib = { name: 'Sakib', age: 35, }; printName();

যদি আমরা এভাবে কল করি তাহলে কি আশার কথা। undefined কিন্তু আনডিফাইন্ড কেনো। এখানে this.name বলতে তো কিছুই নেই তাহলে ত এরর আশার কথা তাহলে এই this সাম্থিকং ইজ হেপেন তাই সে name নামে কিছু পাচ্ছে না তাই এরর না দিয়ে undefined দিচ্ছে। আচ্ছা তাহলে this কে console.log(this) করে দেখা যাক।

আমার এখানে Window অব্জেক্টকে পেয়ে যাবো। তাহলে কি বোঝা গেলো যদি উপরের চারটির মধ্যে কোনো প্রথম তিনটি কোনো রুলই গ্রহন হবে জাভাস্ক্রিট নিজে নিজে this Window কে পয়েন্ট করবে। এখন এটাকে থামাতে হলে অন্তত্য পক্ষে এরর দিয়ে সাবধান করার জন্য আমরা স্ক্রিপ এর সবার উপরে 'use strict' ব্যবহার করতে পারি। এই যে এখানে this window কে পয়েন্ট করছে এটাই হচ্ছে window binding। এটাকে সিউর হবার জন্য আমার এভাবে লিখে দেখতে পারি কাকে শো করে।

var printName = function () { console.log(this); console.log(this.name); //output - undefined }; var sakib = { name: 'Sakib', age: 35, }; printName();

দেখবেন কন্সলে Window কেই পাচ্ছি। এছাড়া this === window করলে true পাবো। এই ছিলো this নিয়ে সকল কন্সেপচুয়াল বেপারটা, আশা করি this নিয়ে আর কোনো সমস্যা হবে না। 💘💘