Chapter 23: JavaScript Tricky Concepts
23-1: উল্টাপথের do ... while
মাঝেমধ্যে দুনিয়া উল্টাপথে চলে। এত দিন ছিল আগে শর্ত চেক করবে, তারপর কোড চলবে। do while এসে কাহিনি উল্টায় ফেলছে। কারণ, do...while লুপের স্পেশালিটি হচ্ছে, আগে কোড ব্লক চলে, আর তারপরে শর্ত চেক করে।
প্রথমে কোড এক্সিকিউট হবে, তারপর শর্ত পরীক্ষা করা হবে। এইটার বেনিফিট হচ্ছে, কোড ব্লক কমপক্ষে একবার চলবেই। এই do...while লুপ লিখতে গেলে নিচের মতো করে লিখতে হয়। যেখানে প্রথমে do ব্লক চলবে। তারপর while-এর ভিতরে গিয়ে শর্ত (condition) চেক করবে। যদি শর্ত true হয়, তাহলে কোড ব্লক আবার চালাবে। আর যদি শর্ত false হয়, তাহলে লুপ বন্ধ হয়ে যাবে।
do {
// code block
} while (condition);যখন আমাদের নিশ্চিত করতে হয় যে, কোডটি অন্তত একবার চলবেই চলবে, তখন do...while ব্যবহৃত হয়। কারণ, নরমাল while লুপ বা নরমাল if-এর মধ্যেও যে শর্ত থাকে, সেখানে শর্ত মিথ্যা হলে কোড একবারও চলবে না। যেমন, আমি একটা while লুপ লিখলাম। যেখানে শর্ত হচ্ছে, count ভেরিয়েবলের মান যদি 5-এর চাইতে বড় হয়, তাহলে লুপ চলবে। যেহেতু নিচে আমার কাউন্ট ভেরিয়েবলের মান 1 আছে, তাই নিচের লুপ আমাকে কোনো আউটপুট দিবে না।
let count = 1;
while (count > 5) {
console.log(count);
count++;
}একই ঘটনা ঘটবে for লুপের জন্য। নিচের for লুপের শর্ত একবারও পূরণ হবে না। তাই একবারও কোনো আউটপুট দিবে না।
for (let count = 1; count > 5; count++) {
console.log(count);
}এই সব ক্ষেত্রে আমি যদি চাই, মিনিমাম একবার হলেও কোড চলবে। তাহলে সেইম শর্তের জন্য আমি do... while লুপ চালিয়ে দিবো। নিচের মতো করে—
let count = 1;
do {
console.log(count);
count++;
} while (count > 5);
Output: 1;আর নরমাল do...while তো নরমালভাবেই চলবে। যেখানে শর্ত, যতক্ষণ পর্যন্ত সত্য আছে, ততক্ষণ পর্যন্ত লুপ চলবে। আর যখন শর্ত মিথ্যা হয়ে যাবে, তখন আর লুপ চলবে না।
let count = 1;
do {
console.log(count);
count++;
} while (count <= 5);
Output: 1 2 3 4 5Practice:
- items নামে একটি ভেরিয়েবল থাকবে, যার মান 3। do...while ব্যবহার কর। আর লুপের শর্ত হবে যতক্ষণ items 5-এর বেশি ততক্ষণ লুপ চলবে। লুপের ভিতরে items এর মান কনসোল লগ করে দেখ কোন আউটপুট পাওয়া যায় কিনা।
- এইবার attempts নামে একটা ভেরিয়েবল থাকবে। চেক করবি, এই attempts-এর মান 10-এর নিচে কি না। যদি 10-এর কম হয়, তাহলে do...while লুপ চলবে। এর লুপের ভিতরে attempts-এর মান এক এক করে বাড়বে। আর তুই যখন শুরু করবি, তখন attempts ভেরিয়েবলের প্রাথমিক মান 12।
- name নামে ভেরিয়েবল থাকবে, যার মান হবে "John"। এরপর do...while লুপ চালাবি। লুপের ভিতরে প্রত্যেকবার name-এর পিছনে n যোগ করবি। আর লুপের শর্তে চেক করবি, name-এর length এর মান 10-এর কম কি না। কম হলে লুপ চলতে থাকবে।
23-2: Switch টিপে case জিতো
যদি অনেকগুলা else-if লিখতে হয় এবং সবগুলা শর্তের জন্য সমান সমান হলে কিছু করতে হয়, তাহলে অনেক অনেক else-if লেখা বিরক্তিকর এবং স্লো হতে পারে। যেমন ধর, আমাদের একটা গ্রুপ আছে, সেখানে কার কী পদবি বা ক্ষমতা আছে, সেটার ওপরে নির্ভর করে বিভিন্ন জিনিস করতে পারবে। সেজন্য চাইলে আমরা অনেক else-if লিখতেই পারি নিচের মতো করে—
const role = "moderator";
if (role === "admin") {
console.log("Full control.");
} else if (role === "moderator") {
console.log("Manage posts.");
} else if (role === "member") {
console.log("Post and comment.");
} else if (role === "guest") {
console.log("View only.");
} else {
console.log("Invalid role.");
}
Output: Manage posts.ওপরের if-else দিয়ে কাজ ঠিকই হবে। তবে যদি শর্ত অনেক বেশি হয়ে গেলে কোড পড়তে সমস্যা হয়। একই ভেরিয়েবল বারবার চেক করতে হয়। প্রত্যেক লাইনে role === লিখতে হয়। তুলনা করতে হয়। কোড হালকা একটু স্লো হয়ে যায়।
দাও সুইচ টিপে
সুইচের মেইন আইডিয়া হচ্ছে, কোনো একটা জিনিসের বিভিন্ন মানের জন্য বিভিন্ন কাজ করবে। যে মান আসবে, সেটার ওপরে নির্ভর করে কোন case ওপেন করবে, সেটা ঠিক করবে। সে জন্য switch লেখার পর ব্র্যাকেটের ভিতরে একটা ভেরিয়েবল বা একটা সিম্পল কোড এক্সপ্রেশন লিখবি। মূলত যে জিনিসটার মানের ওপরে নির্ভর করবে, সেটা লিখবি। তারপর দুইটা সেকেন্ড ব্র্যাকেট দিবি।
switch (expression) {
}এই সেকেন্ড ব্র্যাকেটের ভিতরে বিভিন্ন মানের জন্য আলাদা আলাদা কেইস লিখবি।
কেইস লেখার জন্য প্রথমে case লিখবি তারপর একটা মান লিখবি। এরপর একটা কোলন চিহ্ন(😃 দিবি নিচের মতো করে। এরপর এই কেইস বা এই মানের জন্য এক বা একাধিক লাইন কোড লিখবি। আর কেইসের সবশেষ লাইন হবে break, যাতে কেইস শেষ হলে পুরা সুইচ থেকে কোড বের হয়ে যায়।
switch (expression) {
case value1:
// code block
break;
}এই রকমভাবে যতগুলা দরকার কেইস লিখবি। আর সবার শেষে থাকবে default কেইস। আর ডিফল্ট কেইস লেখার জন্য জাস্ট default লিখলেই হবে। কোনো মান বা case লেখা লাগবে না। আর এই default-এর কাহিনি হচ্ছে ওপরের কোনো কেইস যদি ম্যাচ না করে, তাহলে ডিফল্টের পরের কোড ব্লক আউটপুট দিবে। পুরা switch-এর স্ট্রাকচার দেখতে নিচের মতো হবে।
switch (expression) {
case value1:
// code block
break;
case value2:
// code block
break;
default:
// default block
}এইবার একটা উদাহরণ দেখে ফেল। যেখানে একটা গ্রুপের বিভিন্ন রোল বা পদবির মানুষ আছে। কেউ হয়তো মডারেটর, কেউ অ্যাডমিন, কেউ গেস্ট ইউজার আর কেউ নরমাল ইউজার। আর কে কোন ধরনের ইউজার, সেটার ওপর নির্ভর করবে, সে কী ধরনের কাজ করতে পারবে। এই কোড যদি একটা switch দিয়ে লিখে ফেলি, তাহলে কোড দেখতে নিচের মতো হবে—
const role = "moderator";
switch (role) {
case "admin":
console.log("Full control.");
break;
case "moderator":
console.log("Manage posts.");
break;
case "member":
console.log("Post and comment.");
break;
case "guest":
console.log("View only.");
break;
default:
console.log("Invalid role.");
}Practice:
- একটা mobile নামে ভেরিয়েবল থাকবে। সেখানে brand-এর নাম থাকবে। ব্র্যান্ডের ওপরে নির্ভর করে switch দিয়ে ডিফারেন্ট case-এ কনসোল লগ করবি কোন দেশ থেকে সেই ব্র্যান্ড এসেছে। ব্র্যান্ড Apple হলে USA, Samsung হলে Korea, Xiaomi হলে China, আর অন্য কিছু হলে Unknown Source লিখবি।
- browser নামে একটা ভেরিয়েবল থাকবে। সেটার মান Chrome, Brave, Safari বা অন্য কিছু হতে পারে। কনসোল লগ করবে "Best for developers", যদি Chrome হয়, "Privacy focused", যদি Brave হয়, "Apple users' choice", যদি Safari হয়। অন্য কিছু হলে দেখাবে "Unsupported browser"। এইটা কিন্তু প্রথমে if-else দিয়ে করবি। তারপর switch দিয়ে করবি।
- এইবার paymentMethod নামে ভেরিয়েবল থাকবে। সেটার মান cash, credit, debit বা অন্য কিছু হতে পারে। paymentMethod অনুযায়ী কনসোল লগ করবি। cash হলে দেখাবি "Pay with cash", credit হলে দেখাবি "Pay with credit card", debit হলে দেখাবি "Pay with debit card", অন্য কিছু হলে দেখাবি "Invalid payment method"। এইটা switch দিয়ে করবি।
- একটা membership নামে ভেরিয়েবল থাকবে। সেখানে free, silver, gold বা platinum-এর মান থাকবে। membership অনুযায়ী দেখাবি ইউজারের পারমিশন। যেমন, free হলে "Access limited content", silver হলে "Access most content", gold হলে "Access premium content", platinum হলে "Full access"। এইটা শুধু if-else দিয়ে করবি।
- অনলাইনে কোন কিছু অর্ডার দিলে orderStatus থাকে। তাই এই orderStatus নামে ভেরিয়েবল থাকবে। সেটা pending, shipped, delivered বা cancelled হতে পারে। status অনুযায়ী কনসোল লগ করবি। যেমন, pending হলে "Your order is being processed", shipped হলে "Your order is on the way", delivered হলে "Your order has been delivered", cancelled হলে "Your order was cancelled".
- একটা grade নামে ভেরিয়েবল থাকবে। সেটার মান A, B, C, D বা F হতে পারে। গ্রেড অনুযায়ী দেখাবি ইউজারের ফলাফল। A হলে "Excellent", B হলে "Good", C হলে "Average", D হলে "Poor", F হলে "Fail"।
23-3: with eval ইবলিস
জাভাস্ক্রিপ্টে ইচ্ছামতো লিখে কোড চালানোর একটা ডেঞ্জারাস সিস্টেম আছে। এইটা সাধারণভাবে ইউজ করতে না করে এবং খুব অল্পকিছু কাজ ছাড়া এইটার তেমন দরকারও পড়ে না। আর এইটার নাম eval ফাংশন। কেউ কেউ এইটার বিষয়ে সতর্ক করে বলে evil eval বা eval ইবলিস।
eval এমন একটা ফাংশন, যেটা ইনপুট হিসেবে যেকোনো স্ট্রিং নিবে, আর সেটাকে কোডের মতো এক্সিকিউট করবে। এইটা একটা সুপার পাওয়ার, আবার এইটার কারণে অনেক উল্টাপাল্টা হয়ে যেতে পারে। খারাপ ইন্টেনশনের কোনো ইউজার এসে ভিতরের সেটিংস মুছে দিতে পারে। মান চেইঞ্জ করে দিতে পারে।
const num = 5;
eval("console.log(num + 5)");
Output: 10;এখানে eval() স্ট্রিং হিসেবে পাইছে "console.log(num + 5)"-কে। তারপর সেটাকে কোডের মতো রান করে আউটপুট 10 দিছে। এইটুক পর্যন্ত ভদ্র আছে। তবে কেউ যদি ইউজার ইনপুট হিসেবে দিয়ে দেয়—
let user = 'regular dude';
const userInput = "user = 'Hacker!'";
eval(userInput);
console.log(user);
Output: Hacker!তাহলে কিন্তু ইউজারের তথ্য বা অন্য অনেক গুরুত্বপূর্ণ জিনিস eval করে হাতিয়ে নিতে পারবে বা নষ্ট করতে পারবে। তাই eval ইউজ করাকে বেশির ভাগ সময় evil মনে করে অনেকেই।
এসব কারণে eval() ব্যবহার না করাই বুদ্ধিমানের কাজ। এটা সিকিউরিটি ঝুঁকি বাড়ায়, আর কোড স্লো করে। ডিবাগিংয়ে সমস্যা তৈরি করে।
with কী?
with হলো জাভাস্ক্রিপ্টের একটা স্টেটমেন্ট, যেটা কোনো অবজেক্টের ইচ্ছামতো স্কোপ সেট করার জন্য ইউজ করা যায়। সহজভাবে বলতে গেলে, with তোর কোডের স্কোপের মতো কাজ করে।
const person = { name: "John", age: 30 };
with (person) {
console.log(name);
console.log(age);
}
Output: John;
30;with (person)-এর ভেতরে name আর age সরাসরি কল করা যাচ্ছে। কারণ, person অবজেক্টের প্রোপার্টি সরাসরি অ্যাক্সেস করছে।
with-এর কারণে কিছু সমস্যা হয়। যেমন, with স্কোপে নতুন ভেরিয়েবল থাকলে জাভাস্ক্রিপ্ট ঠিকমতো বুঝতে পারে না, কোনটা with-এর স্কোপের, আর কোনটা গ্লোবাল বা লোকাল।
const name = "Jane";
const person = { name: "John" };
with (person) {
console.log(name);
}
Output: John;এখানে name কোনটা? John না Jane?
কোডে with ব্যবহার করলে এরর বা বাগ খুঁজে বের করা অনেক জটিল হয়ে যায়। সেজন্য মডার্ন জাভাস্ক্রিপ্টে স্ট্রিক্ট মোড ('use strict') ব্যবহার করলে with ইউজ করা যায় না। তাই with-এর পরিবর্তে সরাসরি অবজেক্ট প্রোপার্টি অ্যাক্সেস করা ভালো।
Practice:
- with কী? এইটা কী কাজ করে?
- eval() কী জিনিস। এইটা কেন ইউজ করা উচিত না।
23-4: জাভাস্ক্রিপ্ট অঙ্ক বুঝে না
JavaScript-এ যখন 0.1 আর 0.2 যোগ করা হয়, তখন 0.3 হওয়ার কথা, কিন্তু আসলে 0.1 + 0.2 = 0.30000000000000004 হয়ে যায়। এটা কেন হয়?
const result = 0.1 + 0.2;
console.log(result);
Output: 0.30000000000000004;এইসব সিম্পল যোগ অঙ্ক ভুল করার কারণে মাঝেমধ্যে কোম্পারিজন ঠিক হয় না। তুলনা গড়বড় হয়ে যায়
const first = 0.1;
const second = 0.2;
if(first + second === 0.3){
console.log('they are same');
}
else {
console.log('they are not the same');
}
Output: they are not the sameএকটা তুলনা ভুল হয়ে গেলো। 0.1 আর 0.2 যোগ করলে 0.3 এর সমান হলো না। যদিও আসল ফলাফল 0.30000000000000004 আর এক্সপেক্টেড ফলাফল এর মধ্যে ডিফারেন্স খুবই কম। তারপরেও শর্ত কিন্তু ঠিক না হয়ে ভুল হয়ে গেলো। কি বিপদ!
কেন এই সমস্যা হয়?
জাভাস্ক্রিপ্ট floating point arithmetic ব্যবহার করে। আর এই পদ্ধতির মধ্যে decimal numbers (যেমন: 0.1, 0.2, 0.3)-কে বাইনারি (2-এর ভিত্তিতে) রূপে রূপান্তরিত করা হয়। কিন্তু বাইনারিতে অনেক দশমিক সংখ্যা সঠিকভাবে রূপান্তর করা যায় না। এখানে মূল সমস্যা হচ্ছে, কিছু দশমিক সংখ্যা বাইনারি ফর্মেটে এক্স্যাক্টলি মাপানো সম্ভব হয় না, যার ফলে প্রিসিশন লস (precision loss) হয়।
কীভাবে সংখ্যা রূপান্তরিত হয়?
যেমন: আমরা বলি, 0.1-কে বাইনারি ফর্ম্যাটে কনভার্ট করতে গেলে সেটা হবে—
0.1 = 0.00011001100110011... (অনন্ত দশমিক)
এখানে, 0.1-এর বাইনারি রূপ আসলে finite নয়, অর্থাৎ এটা অনন্ত ডিজিট পর্যন্ত চলে এবং কম্পিউটার তো সেই অনন্ত ডিজিটের সঠিক মান সেভ করতে পারবে না, তাই তা approximate (আনুমানিক) হয়ে যায়। একইভাবে 0.2-এরও ঠিক একই সমস্যা আছে। এর বাইনারি রূপও কিছুটা দীর্ঘ এবং পূর্ণভাবে সঠিকভাবে প্রকাশ করা সম্ভব নয়।
ফলে কী হয়?
অতএব 0.1 আর 0.2 যখন যোগ করা হয়, তখন কম্পিউটার তাদের আনুমানিক বাইনারি মানগুলিকে যোগ করে, কিন্তু যোগফল ঠিক 0.3 হয় না; বরং একটি ছোটখাটো ত্রুটি আসে, যা 0.30000000000000004-এর মতো কিছু হয়ে ওঠে।
যেহেতু floating point-এর মধ্যে ছোট ছোট গুণগত পার্থক্য থাকতে পারে, তাই এমন ধরনের ত্রুটি ঘটে। তবে সাধারণত toFixed() বা toPrecision() ব্যবহার করে এভোয়েড করা যায়।
let result = (0.1 + 0.2).toFixed(1);
console.log(result);
Output: 0.3;এই toFixed করে তুলনা করাও যায়।
const first = 0.1;
const second = 0.2;
if ((first + second).toFixed(1) === (0.3).toFixed(1)) {
console.log('they are same');
} else {
console.log('they are not the same');
}
Output: they are sameএই সমস্যা শুধু জাভাস্ক্রিপ্ট এ না বরং পাইথন, জাভা, php এমনকি C++ এও হয়। কারণ এদের সবাই সেইম স্টাইলেই floating point arithmetic ইউজ করে।
23-5: if যদি IIFE হয়
বড় বড় মন্ত্রী মিনিস্টার দেখবি সমাবেশে এসে দ্রুত তার বক্তৃতা দিয়ে সাথে সাথে চলে যাচ্ছে। ডাইনে বায়ে কোন কিছু খোঁজ নিচ্ছে না। একইভাবে ভার্সিটির ভিসি স্যারকেও দেখবি অনেক কিছু করতে হয়। কখনো মিটিংয়ে এসে দ্রুত ওনার কাজ করে চলে যেতে হয়। একইভাবে কোন কারণে তোর আব্বুকে যদি অফিস টাইমে বাসায় আসতে হয় তাহলে দ্রুত জরুরি কাজটা শেষ করে তারপর চলে যেতে হয়।
জাভাস্ক্রিপ্টেও দ্রুত আলাদাভাবে কাজ করে ফেলার একটা সিস্টেম আছে যেটাকে ছোট করে IIFE বলে। এইটার বড় নাম হচ্ছে - Immediately Invoked Function Expression এই নামের প্রথম অক্ষরগুলো নিয়ে হয় IIFE
IIFE এর কাজ হচ্ছে এমন একটা ফাংশন তৈরি হবে, যেটা ইমিডিয়েটলি সাথে সাথেই এক্সিকিউট হয়ে যাবে। এবং সাথে সাথে কাজ শেষ। আগে পরে কিছু নাই। এবং পরে ওই ফাংশন নিয়ে কিছু করার দরকারও পড়বে না। অর্থাৎ সে আলাদা একটা জগৎ তৈরি করে কাজ শেষ করে ফেলবে।
ভিতর বলে দূরে থাকো
কোন একটা ছোট কোডকে আলাদা করার জন্য, সেইফ এবং ক্লিন রাখার জন্য IIFE খুবই গুরুত্বপূর্ণ। অনেক সময় ভ্যারিয়েবল বা ফাংশনের নাম কনফ্লিক্ট হতে পারে। অর্থাৎ একইনাম একাধিকবার চলে আসতে পারে। সেসব ক্ষেত্রে IIFE ব্যবহার করলে এর ভেতরের কোড বাইরের কোড থেকে আলাদা থাকে। ভিতর আর বাহিরের কোড মারামারি করতে পারবে না।
আরেকটু সিরিয়াসলি বললে-- IIFE এর মাধ্যমে একটি আলাদা scope তৈরি করা যায়। এর ফলে বাইরে থেকে কোনো ভ্যারিয়েবল বা ডেটা ঐ scope-এ অ্যাক্সেস করা যায় না।
আবার কিছু কোড এমন থাকে যা শুধুমাত্র একবারই রান করতে হয়। এই ক্ষেত্রে IIFE খুব কাজে আসে।
দৌড়ের উপরে IIFE
নরমাল একটা ফাংশন লিখলে আমরা function কীওয়ার্ড লিখি তারপর নাম দিয়ে লিখি। এরপর প্যারামিটার দেয়ার জায়গা থাকে, ফাংশনের বডি থাকে। তারপর এই ফাংশনকে কল করার জন্য আমরা ফাংশন এর নাম লিখে তারপর দুইটা ব্রাকেট দিয়ে ফেলি।
function sayHello() {
console.log("Hello!");
}
sayHello();খেয়াল করবি ফাংশন কল করার জন্য আমরা ফাংশনের নামের পর দুইটা প্রথম ব্রাকেট () দিয়ে ফেলি। বিশেষ করে যখন ফাংশনের মধ্যে কোন প্যারামিটার না থাকে। IIFE লিখতে গেলে ফাংশন এর নাম দেয়ার দরকার নাই। এবং পুরা ফাংশনকে একটা এক্সপ্রেশন এর মধ্যে রাখতে হবে। অনেকটা (function() { ... }) এই স্টাইলে। তারপর সাথে সাথে কল করার জন্য দুইটা প্রথম ব্রাকেট () দিয়ে দিতে হবে। যাতে ফাংশন লেখার সাথে সাথেই এই ফাংশন কল হয়ে যায়। সেজন্যই এইটাকে বলে ইমিডিয়েট ইনভোক হচ্ছে। অথাৎ ফাংশন ইমিডিয়েটলি রান করতেছে।
এই ফাংশন ইমিডিয়েটলি রান হচ্ছে, অর্থাৎ পরে কেউ এইটাকে আলাদাভাবে কল করবে না। তাই এই ফাংশনের কোন নামের দরকার নাই। আর সাথে সাথে এই ফাংশনকে কল করার জন্য এইটাকে একটা ফাংশন এক্সপ্রেস বানিয়ে ফেলছে। সেইজন্য এইটার পুরা নাম হচ্ছে Immediately Invoked Function Expression বা ওরফে IIFE
এইটার একটা উদাহরণ দেখে ফেলি
(function() {
console.log("This is an IIFE!");
})();
Output: This is an IIFE!কেউ ফাংশনকে কল করা লাগে নাই। বরং সাথে সাথে ইন্সট্যান্টলি আউটপুট দিয়ে দিছে।
আর যদি অ্যারো ফাংশন দিয়ে IIFE লিখতে যাস তাহলে এইভাবে লিখে ফেলবি। সেইম স্টাইলে জাস্ট নরমাল ফাংশনের জায়গায় অ্যারো ফাংশন হবে।
(() => {
console.log("Arrow function IIFE !");
})();
Output: Arrow function IIFE !কেন IIFE দরকার?
অনেক সময় এক কাজ একবারই করতে হয় তখন IIFE খুব কাজে লাগে। যেমন, তুই কোন একটা সফটওয়্যার স্টার্ট করবি। যেটাকে বলে initialize করবি। তো এই ইনিশিয়ালাইজ এর কাজ কিন্তু একবারই হবে। অর্থাৎ তুই মোবাইল অন করার সময় যা যা সেট করা দরকার সেগুলা কিন্তু একবারই করতে হবে। এইসব ক্ষেত্রে IFFE খুব দরকার হয়।
(function() {
console.log("Application initializing...");
// Perform some setup
})();
Output: Application initializing...আবার যেমন একটা ফাইল লোড করবো। একই ফাইল বারবার লোড করবো না। সেক্ষেত্রেও IIFE খুব কাজে দিবে। নিচের কোড পুরাপুরি না বুঝলেও IIFE এর প্রয়োজনীয়তা কিন্তু ঠিকই বুঝতে পারবি।
(function () {
const script = document.createElement("script");
script.src = "https://example.com/library.js";
script.onload = function () {
console.log("Library loaded!");
};
document.head.appendChild(script);
})();Dependency injection
বেশিরভাগ সময় IIFE কোন প্যারামিটার নেয় না। এবং আউটসাইড এর সাথে কোন কিছুর সাথে গেস্টাগেষ্টি করে না। তবে মাঝে মধ্যে দরকার হলে গ্লোবাল কোন কিছু বা কোন প্যারামিটার পার করতে হয়। সেই পার করার সিস্টেম নরমাল ফাংশনের মতো হলেও প্রথমে দেখতে একটু অদ্ভুত লাগবে কিন্তু একটু খেয়াল করলে নরমাল লাগবে।
বিষয়টা হচ্ছে, নরমাল ফাংশনে যেখানে প্যারামিটার ডিক্লেয়ার করবি, এইখানেও সেইভাবেই করবি। নরমাল ফাংশনে function কীওয়ার্ড এবং তার নাম লেখার পর ব্রাকেটের ভিতরে প্যারামিটার সেট করে। এইখানেও সেইম হিসাব। তবে এইখানে নাম যেহেতু নাই এবং function কীওয়ার্ড এর পর ব্রাকেটের ভিতরে লিখে ফেলবি।
(function (global) {})();এইটা তো প্যারামিটার ডিক্লেয়ার করলি।
নরমাল ফাংশনে শুধু প্যারামিটার ডিক্লেয়ার করলে কাজ হয় না। ফাংশন কল করার সময় আর্গুমেন্ট হিসেবে সেটার মান পাঠাতে হয়। এইখানেও সেইম কাজ করতে হবে। ফাংশন কল যেহেতু ডিক্লেয়ার করার সাথে সাথেই হয়। তাই লাস্ট যে দুইটা প্রথম ব্রাকেট আছে সেটার ভিতরে IIFE এর প্যারামিটার দিয়ে দিতে হবে। নিচে আমরা IIFE কে window অবজেক্ট আর্গুমেন্ট হিসেবে পাস করে কল করতেছি। যাতে IIFE এর ভিতরে window কে global নাম দিয়ে ইউজ করতে পারি।
(function (global) {})(window);একই সিস্টেমে তুই চাইলে একাধিক আর্গুমেন্ট পাস করতে পারবি।
ফাইনাল কথা হচ্ছে IIFE মানে Immediately Invoked Function Expression– মানে যে ফাংশন সাথে সাথে এক্সিকিউট হয়ে যাবে। হয়ে গিয়ে কাজ শেষ।
Practice:
- IIFE কি জিনিস? এইটা কেন ইউজ করা হয়।
- একটা IIFE বানা যেটা নিজে থেকে console এ "I am isolated from outer scope!" প্রিন্ট করবে।
- অ্যারো ফাংশন দিয়ে একটা IIFE বানা, যেটা প্রিন্ট করবে "borrow from arrow"।
- একটা IIFE বানা যেটা temperature প্যারামিটার নেবে এবং কেলভিন থেকে সেলসিয়াসে কনভার্ট করবে। কনভার্ট করার ফর্মুলা হলো: celsius = kelvin - 273.15। তারপর কনভার্ট করা মানটা প্রিন্ট কর।
23-6: use strict-এর কড়া স্যার
সব স্কুলেই কড়া একজন স্যার থাকেন। স্যারের সামনে একদম সব স্টুডেন্ট আতঙ্কের মতো থাকে। কোনো টু শব্দ নাই। কেউ কোনো দুষ্টুমি-বাঁদরামি করার চিন্তাও করে না। এমনকি একটা মাছি-মশাও স্যারের সামনে আসার কথা চিন্তা করে না। জাভাস্ক্রিপ্টেও এমন একটা কড়া স্যার আছে। খুবই কড়া। খুবই স্ট্রিক্ট।
এই স্ট্রিক্ট হওয়ার জন্য হয় জাভাস্ক্রিপ্টের ফাইলের প্রথম লাইন হিসেবে "use strict" লিখে দিতে পারস। তাহলে পুরা ফাইলের সব কোড স্ট্রিক্ট মোডে চলবে। একইভাবে তুই চাইলে একটা ফাংশনের ভিতরে প্রথম লাইন হিসেবে "use strict" লিখে দিতে পারস। তাহলে সেই ফাংশনের ভিতরের সব কোড স্ট্রিক্ট মোডে চলবে।
এ ছাড়া ES6-এর মডিউলে ডিফল্টভাবে স্ট্রিক্ট মুড অন করা থাকে। তাই ES6-এর মডিউলে আলাদাভাবে "use strict" লিখতে হয় না।
১. ভেরিয়েবল ডিক্লেয়ার না করলে এরর
কোনো একটা ভেরিয়েবল ডিক্লেয়ার করার আগে আমরা const বা let লিখি। কিন্তু কখনো যদি ভুলে let const না লিখি নরমাল একটা জাভাস্ক্রিপ্ট ফাইলে, সে কিন্তু কাজ করবে এবং একটু সমস্যা করে ফেলবে। সে ভিতরে ভিতরে গ্লোবাল ভেরিয়েবল হয়ে যাবে। অর্থাৎ পুরা কোডের সব জায়গা থেকে তাকে এক্সেস করা যাবে।
মাঝেমধ্যে অল্প কয়েকটা গ্লোবাল ভেরিয়েবলের দরকার হয়। তবে অনিচ্ছাকৃতভাবে গ্লোবাল ভেরিয়েবল তৈরি করা উচিত না। এতে প্রোগ্রমিংয়ের মেমোরি ম্যানেজমেন্টে সমস্যা হয়। আবার অনেক ক্ষেত্রে একই নাম একাধিক জায়গায় কনফ্লিক্ট করে ফেলে। ভুল মান দিতে পারে, আরও অনেক সমস্যা।
তাই "use strict" ইউজ করলে নরমাল জাভাস্ক্রিপ্ট ফাইলেও কিন্তু এরর দিয়ে বসবে।
'use strict';
x = 10;
Output: ReferenceError: x is not definedভেরিয়েবল সব সময় let বা const দিয়ে ডিক্লেয়ার করতে হবে।
২. ডুপ্লিকেট প্যারামিটার
এমন কোনো কারণ নাই যে, কোনো একটা ফাংশনে একই নামে একাধিক প্যারামিটার থাকবে। তারপরেও কেউ এইটা করে ফেললে নরমাল জাভাস্ক্রিপ্ট কোনো কিছু বলবে না। তবে স্ট্রিক্ট মুডে থাকলে সে এরর দিয়ে দিবে।
"use strict"
function add(a, a){
}
Output: SyntaxError: Duplicate parameter name not allowed৩. this নাই
নরমাল জাভাস্ক্রিপ্টে ফাংশনের ভিতরের this গ্লোবাল অবজেক্টকে (যেমন ব্রাউজারে window) বুঝায়, এতে মাঝেমধ্যে কিছু কনফিউশন চলে আসতে পারে। তাই স্ট্রিক্ট মোড এটা বন্ধ করে দেয় এবং স্ট্রিক্ট মোডে ফাংশনের ভিতরে this যদি কোনো অবজেক্টের অংশ না হয়, তাহলে এটা undefined হবে।
"use strict";
function getContext() {
console.log(this);
}
getContext();
output: undefined;এই রকম আরও অনেকগুলা রেস্ট্রিকশন থাকে স্ট্রিক্ট মুডে। যেমন, জাভাস্ক্রিপ্টে কিছু রিজার্ভড ওয়ার্ড (যেমন private, protected, interface, package, implements) আছে, যেগুলা ফিউচারে ইউজ করার জন্য রেখে দিছে। নরমাল জাভাস্ক্রিপ্টে এই নামগুলো ইউজ করে ভেরিয়েবল ডিক্লেয়ার করা যায়। কিন্তু স্ট্রিক্ট মুডে এই নামগুলো দিয়ে ভেরিয়েবল ডিক্লেয়ার করা যায় না।
Practice:
- স্ট্রিক্ট মুড কেন ইউজ করা হয়?
