সরাসরি পর্বে যান
পর্ব ০৪ · ৫৯-এর মধ্যে · মডিউল ১

প্রথম প্রোগ্রাম — console.log থেকে পাতায় লেখা

Your First JavaScript Program — console.log, Writing to the Page & Reading Errors

Taught in Bangla, this lesson writes a first JavaScript program: code running top to bottom, console.log as the developer's window, statements, semicolons and automatic semicolon insertion pitfalls, comments, case sensitivity and naming rules, writing output to the page for users, reading error messages, and a small bazaar bill-splitting project.

এই পর্বে যা শিখবেন

  • Engine কীভাবে একটি ফাইল পড়ে আর statement একটার পর একটা চালায়
  • console.log, string, number আর ছোট হিসাব — আর semicolon-এর আসল নিয়ম (ASI)
  • Comment, বড়-ছোট হাতের অক্ষর, নাম রাখার নিয়ম আর "use strict" কেন আছে
  • querySelector + textContent দিয়ে পাতায় লেখা, আর কোন পুরোনো উপায়গুলো এড়াবেন
  • ReferenceError, SyntaxError আর TypeError পড়ে ধাপে ধাপে ঠিক করা — browser ও Node দুই জায়গাতেই

১ · প্রোগ্রাম মানে ওপর থেকে নিচে চলা নির্দেশের সারি

আগের পর্বে আপনি browser console আর Node.js হাতের কাছে এনেছেন। এবার প্রথম প্রোগ্রাম। তবে কোড লেখার আগে একটি ছবি মাথায় বসিয়ে নিন — বাকি পুরো কোর্স এই ছবির ওপর দাঁড়িয়ে।

একটি JavaScript প্রোগ্রাম হলো কতগুলো statement-এর সারি। প্রতিটি statement একটি সম্পূর্ণ নির্দেশ: “একটি মান মনে রাখো”, “এটা যোগ করো”, “এটা দেখাও”। যে প্রোগ্রাম এই নির্দেশগুলো পড়ে চালায়, তার নাম engine — Chrome ও Edge-এ V8, Firefox-এ SpiderMonkey, Safari-তে JavaScriptCore. Node.js-এর ভেতরেও আছে সেই V8.

চায়ের দোকানে নতুন একজন সহকারী এসেছেন। মালিক একটি কাগজে লিখে দিলেন: “১. কেতলিতে পানি দাও। ২. চুলা জ্বালাও। ৩. পাতা দাও। ৪. কাপে ঢালো।” সহকারী ওপর থেকে নিচে, একটি একটি করে কাজ করেন। তিন নম্বরের আগে চার নম্বর করেন না, আর কাগজে যা লেখা নেই তা নিজে থেকে করেন না। Engine ঠিক এই সহকারী — অক্ষরে অক্ষরে, ক্রম মেনে।

একটি সূক্ষ্ম কিন্তু জরুরি কথা: engine প্রথম লাইন চালানোর আগে পুরো ফাইলটি একবার পড়ে নেয়, ব্যাকরণ ঠিক আছে কি না দেখতে। একে বলে parsing. ব্যাকরণ ঠিক থাকলে তবেই চালানো শুরু। এই দুই ধাপের কথা মনে রাখুন — অংশ ৬-এ error পড়ার সময় এটাই চাবিকাঠি হবে। নিচের ডায়াগ্রামে একটি বাজারের হিসাব কীভাবে ধাপে ধাপে চলে দেখুন:

1let total = 0;2total = total + 320;   // চাল3total = total + 145;   // ডাল4console.log('এখন পর্যন্ত:', total);5total = total + 199;   // তেল6console.log('মোট:', total);
ভ্যারিয়েবলের মান
total
  1. আগে পুরো ফাইল পড়া (parsing). সব লাইন একসাথে দাগানো — engine এখনো কিছু চালায়নি, শুধু ব্যাকরণ মিলিয়ে দেখছে। total নামে কিছু এখনো মেমরিতে নেই। কোথাও একটি বন্ধনী কম থাকলে এখানেই থেমে যেত, একটি লাইনও চলত না।
  2. লাইন ১ চলল। দাগানো লাইনটি এইমাত্র চলেছে। let total = 0 — “total নামে একটি জায়গা বানাও, তাতে 0 রাখো।” let নিয়ে বিস্তারিত পর্ব ০৭-এ।
  3. লাইন ২. ডান দিক আগে হিসাব হয়: total (0) + 320 = 320, তারপর সেই ফল total-এ বসে। = এখানে “সমান” নয়, “বসাও”।
  4. লাইন ৩. 320 + 145 = 465. একই নাম, নতুন মান — পুরোনো 320 মুছে গেছে।
  5. লাইন ৪ — প্রথম আউটপুট। console.log সেই মুহূর্তের মান দেখায়: 465. পরে total বদলালেও এই লাইন আর বদলাবে না — console-এ যা লেখা হয়ে গেছে, তা ইতিহাস।
  6. লাইন ৫. 465 + 199 = 664. লক্ষ করুন, console-এ এখনো 465 — কারণ লাইন ৪ আগেই চলে গেছে।
  7. লাইন ৬ — শেষ। “মোট: 664” ছাপা হলো। ফাইলের শেষে পৌঁছে engine থামল। একটি সহজ পরীক্ষা: লাইন ৪ আর ৬-এর জায়গা বদলালে আউটপুট কী হতো? ক্রমই অর্থ।

১৯৯৫ সালের মে মাসে Netscape-এ Brendan Eich মাত্র দশ দিনে JavaScript-এর প্রথম সংস্করণ বানান। তখন লক্ষ্য ছিল ছোট ছোট স্ক্রিপ্ট — একটি ফর্ম যাচাই, একটি ছবি বদলানো। সেজন্যই ভাষাটি আজও “ভুল হলেও যতটা পারো চালিয়ে যাও” মনোভাব বহন করে। এই পর্বে সেই মনোভাবের কয়েকটি চিহ্ন দেখবেন — স্বয়ংক্রিয় semicolon, আর "use strict" দিয়ে তার সংশোধন।

C/C++/Python/Java জানলে

C বা Java-তে প্রোগ্রাম শুরু হয় main() থেকে, আর চালানোর আগে আলাদা compile ধাপ লাগে। JavaScript-এ main নেই — ফাইলের প্রথম লাইন থেকেই চলা শুরু, অনেকটা Python-এর মতো। Semicolon Java/C-তে বাধ্যতামূলক, Python-এ নেই, আর JavaScript-এ “ঐচ্ছিক, কিন্তু নিয়ম জেনে”। তুলনার জন্য দেখুন C কোর্সের প্রথম প্রোগ্রাম আর Java কোর্সের প্রথম প্রোগ্রাম.

২ · console.log — ডেভেলপারের জানালা

প্রথম প্রোগ্রামটি এক লাইনের। Browser console (F12 → Console) বা Node.js-এ লিখুন:

console.log('Hello, World!');

এখানে console একটি object — DevTools-এর console প্যানেলের সাথে কথা বলার মাধ্যম। তার ভেতরের log একটি function, যা পাওয়া মান লিখে দেয়। বন্ধনীর ভেতরে যা দেন, তাকে বলে argument. কমা দিয়ে একাধিক argument দেওয়া যায়; console.log সেগুলো মাঝে একটি করে ফাঁকা রেখে পাশাপাশি লেখে।

মূল ধারণা

Console হলো ডেভেলপারের জানালা। সাধারণ ব্যবহারকারী কখনো F12 চাপেন না — তাঁরা console-এর লেখা দেখেনই না। তাই console.log দিয়ে আপনি নিজের জন্য নোট রাখেন: “এখানে মান কত?”, “এই লাইন পর্যন্ত এলো কি?” ব্যবহারকারীকে কিছু দেখাতে হলে লিখতে হবে পাতার ওপর — সেটি অংশ ৫-এ।

String, number আর ছোট হিসাব

উদ্ধৃতিচিহ্নের ভেতরের লেখাকে বলে string. একক '…', দ্বৈত "…" আর backtick `…` — তিনটিই চলে; শুধু শুরু আর শেষে একই চিহ্ন হতে হবে। উদ্ধৃতি ছাড়া 42 বা 12.5 হলো number. আর 45 + 30-এর মতো যা হিসাব করে একটি মান দেয়, তাকে বলে expression. নিচের টেবিলের প্রতিটি ফল Edge আর Node-এ চালিয়ে যাচাই করা:

লিখলেনConsole-এ এলোকেন
console.log('Hello', 'Dhaka', 42, true)Hello Dhaka 42 trueচারটি argument, মাঝে ফাঁকা
console.log(2 + 3)5দুটি number — যোগ
console.log("2" + 3)23একটি string থাকলে + জোড়া দেয়
console.log('5' * 2)10* string-কে number বানিয়ে নেয় — পর্ব ০৬-এর “coercion”
console.log(0.1 + 0.2)0.30000000000000004দশমিকের binary রূপ — পর্ব ১০-এ বিস্তারিত
console.log((0.1 + 0.2).toFixed(2))0.30toFixed(2) দুই ঘর দশমিকের string দেয়

শেষ দুটি সারি টাকার হিসাবে খুব কাজের। দাম দেখানোর সময় toFixed(2) দিয়ে দুই ঘর দশমিক রাখুন, যাতে “271.3333333333333 টাকা” না দেখায়। মনে রাখবেন, toFixed ফেরত দেয় string — অর্থাৎ দেখানোর জন্য, আরও হিসাবের জন্য নয়।

Console-এর আরও কয়েকটি ভাই আছে: console.error (লাল), console.warn (হলুদ), console.table (টেবিল আকারে)। শুরুতে console.log-ই যথেষ্ট। তবে আসল প্রজেক্টে কাজ শেষে অপ্রয়োজনীয় console.log মুছে ফেলুন — ব্যবহারকারীর browser-এ আবর্জনা রেখে যাওয়া পেশাদার অভ্যাস নয়।

৩ · Statement, semicolon আর ASI-এর ফাঁদ

C বা Java-তে প্রতিটি statement-এর শেষে ; না দিলে compile-ই হয় না। JavaScript-এ অনেক সময় না দিলেও চলে। কারণ ভাষার নিয়মে আছে ASI — Automatic Semicolon Insertion. মোটামুটি নিয়ম: লাইন ভাঙার জায়গায় পরের টোকেন দিয়ে আগের statement চালিয়ে নেওয়া না গেলে, engine সেখানে নিজেই একটি ; ধরে নেয়।

শুনতে আরামদায়ক। কিন্তু দুটি জায়গায় এটি উল্টো কাজ করে — একবার বসিয়ে দিয়ে, আরেকবার না বসিয়ে। নিচে দুটোই আসল আচরণসহ দেখুন:

bill.jsআপনি যা লিখেছেন
function getBill() {
  return
  {
    total: 120
  };
}
console.log(getBill());
engine-এর চোখেreturn-এর পরেই লাইন ভাঙা
function getBill() {
  return;          // ← ASI এখানে ; বসাল
  {
    total: 120
  };
}
নিচের অংশটা তাহলে কী?object নয়, একটি block
  {                 // একটি block
    total: 120      // label "total" + মান 120
  };                // কখনো চলবে না
Console (Edge ও Node)ফল
undefined

// ঠিক করার উপায়: { থাকুক return-এর লাইনেই
return {
  total: 120
};
উল্টো ফাঁদASI যখন ; বসায় না
const a = 1
const b = a
[1, 2].forEach(n => console.log(n))

// engine পড়ে: const b = a[1, 2].forEach(...)
TypeError: Cannot read properties of undefined (reading 'forEach')
  1. দেখতে নিরীহ কোড। একটি function একটি object ফেরত দিতে চায় — { total: 120 }. অনেকে কোঁকড়া বন্ধনী নতুন লাইনে রাখেন (C# বা কিছু C স্টাইলে এটাই রীতি)। আশা: console-এ { total: 120 }.
  2. return-এর পরে লাইন ভাঙা নিষেধ। ভাষার নিয়মে কয়েকটি শব্দের পরে লাইন ভাঙা চলে না — return, break, continue, throw ইত্যাদি। এদের পরে লাইন ভাঙলে ASI সাথে সাথে ; বসায়। ফলে statement-টি হয়ে গেল শুধু return; — কিছুই ফেরত দেয় না।
  3. বাকি অংশ object নয়! নতুন লাইনের { engine-এর চোখে একটি block. ভেতরের total: হয়ে গেল একটি label, আর 120 একটি একা মান। কোনো error নেই — শুধু কোডটি কখনো চলবে না। মজার তথ্য: ভেতরে দুটি property (total: 120, items: 4) থাকলে এটি আর বৈধ block থাকে না, তখন SyntaxError: Unexpected token ':' আসে — অন্তত সমস্যাটি চোখে পড়ে।
  4. ফল: undefined. Edge আর Node — দুই জায়গাতেই চালিয়ে এটিই এসেছে। নিঃশব্দ ভুল, সবচেয়ে বিপজ্জনক ধরন। সমাধান সহজ: { রাখুন return-এর একই লাইনে। JavaScript-এ এই স্টাইলই প্রচলিত।
  5. উল্টো দিক: যেখানে ASI চুপ। পরের লাইন [ বা ( দিয়ে শুরু হলে engine ভাবে আগের লাইনেরই অংশ — তাই ; বসায় না। a[1, 2] মানে a[2], আর 1-এর ভেতরে [2] বলে কিছু নেই, তাই undefined; তার .forEach ডাকতেই TypeError (বার্তাটি Edge ও Node-এ হুবহু এক)। Semicolon ছাড়া লেখেন যাঁরা, তাঁরা এজন্যই এমন লাইনের শুরুতে ; দেন।

এই কোর্সের নিয়ম: প্রতিটি statement-এর শেষে ; দেব, আর return-এর মান সবসময় একই লাইনে শুরু করব। Semicolon দিলেও return-এর ফাঁদ থেকে মুক্তি নেই — সেটি লাইন ভাঙার নিয়ম, semicolon-এর নয়। পর্ব ৪৬-এ Prettier আর ESLint দেখবেন, যারা এসব নিজে থেকেই ধরিয়ে দেয়।

৪ · Comment, বড়-ছোট হাতের অক্ষর আর নামের নিয়ম

Comment — মানুষের জন্য লেখা

Comment engine পুরোপুরি উপেক্ষা করে; এটি পরের পাঠকের জন্য — যিনি ছয় মাস পরের আপনিও হতে পারেন। দুই রকম:

// এক লাইনের comment — লাইনের শেষ পর্যন্ত

/* একাধিক লাইনের comment —
   যেখানে শেষ চিহ্ন আসবে, সেখানেই শেষ */

/**
 * দুই ঘর দশমিকে টাকার অঙ্ক বানায়।
 * @param {number} amount - টাকার পরিমাণ
 * @returns {string} যেমন "271.33"
 */
function formatTaka(amount) {
  return amount.toFixed(2);
}

শেষেরটি /** দিয়ে শুরু — এর নাম JSDoc. VS Code এটি পড়ে: formatTaka( লিখলেই ওপরে বর্ণনা আর টাইপ দেখায়। এটি TypeScript-এর দিকে প্রথম পদক্ষেপও — পর্ব ৪৭-এ আবার দেখা হবে। ভালো comment বলে কেন, কোড নিজেই বলে কী। // total-এ 1 যোগ করো অপ্রয়োজনীয়; // দোকান ১ টাকা রাউন্ড আপ করে, তাই +1 মূল্যবান।

বড় হাত আর ছোট হাত আলাদা

JavaScript case-sensitive — total, Total আর TOTAL তিনটি আলাদা নাম। এক অক্ষরের ভুলে দুই ধরনের error আসে, দুটোই Node-এ চালিয়ে দেখা:

লিখলেনErrorমানে
Console.log('x')ReferenceError: Console is not definedConsole নামে কিছুই নেই
console.Log('x')TypeError: console.Log is not a functionconsole আছে, কিন্তু তার ভেতরে Log নেই — undefined-কে ডাকা হয়েছে

পার্থক্যটি খেয়াল করুন — এটি অংশ ৬-এর মূল শিক্ষা। নামটাই না পেলে ReferenceError; নাম পাওয়া গেছে কিন্তু সেটি দিয়ে অসম্ভব কাজ করতে বললে TypeError.

নাম রাখার নিয়ম (identifier)

ভ্যারিয়েবল বা function-এর নামকে বলে identifier. নিয়ম: অক্ষর, _ বা $ দিয়ে শুরু; পরে অঙ্কও চলে; ফাঁকা বা - চলে না; let, return-এর মতো সংরক্ষিত শব্দ চলে না। Node-এ যাচাই করা উদাহরণ:

  • let 2nd = 1 → SyntaxError: Invalid or unexpected token (অঙ্ক দিয়ে শুরু)
  • let my-name = 1 → SyntaxError: Unexpected token '-' (engine ভাবে বিয়োগ)
  • let let = 1 → SyntaxError: let is disallowed as a lexically bound name

JavaScript-এর রীতি হলো camelCase: প্রথম শব্দ ছোট হাতে, পরের প্রতিটি শব্দের প্রথম অক্ষর বড় — customerName, totalPrice, getBill. Class-এর নাম বড় হাতে শুরু (ShoppingCart), আর কখনো না বদলানো ধ্রুবক অনেকে লেখেন VAT_RATE.

বাংলায় নাম রাখা যায়? হ্যাঁ। ভাষার নিয়ম Unicode-এর অক্ষরকে identifier হিসেবে মানে, আর বাংলা বর্ণ তার মধ্যে পড়ে। Edge আর Node — দুই জায়গাতেই let নাম = 'রাফি'; const মোট_দাম = 45 + 30; চালালে ঠিকঠাক রাফি 75 আসে। তবুও পরামর্শ: নাম রাখুন ইংরেজিতে, বাংলা রাখুন string আর comment-এ। কারণ — অনেক কীবোর্ডে বাংলা টাইপ করে কোড লেখা ধীর; একই দেখতে দুটি বাংলা বানান (যেমন য়/য়-এর ভিন্ন Unicode রূপ) আলাদা নাম হয়ে যেতে পারে; আর দলের অন্য দেশের ডেভেলপার বা টুল সেটি পড়তে পারবে না।

"use strict" — ভাষার পুরোনো ভুলের সংশোধনী

পুরোনো JavaScript-এ একটি ভয়ংকর আচরণ ছিল: ঘোষণা না করা নামে মান বসালে engine চুপচাপ একটি global ভ্যারিয়েবল বানিয়ে ফেলত। ফলে বানান ভুল (totl = 5) কোনো error দিত না, শুধু নতুন একটি ভ্যারিয়েবল জন্ম নিত। ES5 (২০০৯) এর সমাধান আনে strict mode: ফাইল বা function-এর শুরুতে "use strict"; লিখলে এমন ভুল সরাসরি error হয়ে যায়। যাচাই করা ফল: সাধারণ মোডে totl = 5 নিঃশব্দে চলে, কিন্তু strict mode-এ একই লাইনে আসে ReferenceError: totl is not defined — ভুলটি সাথে সাথে চোখে পড়ে।

আধুনিক কোডে প্রায়ই এই লাইনটি আলাদা করে লিখতে হয় না। <script type="module"> বা import/export ব্যবহার করা ফাইল — অর্থাৎ module — আর class-এর ভেতরের কোড নিজে থেকেই strict. Module নিয়ে বিস্তারিত পর্ব ৪৫-এ।

৫ · পাতায় লেখা — ব্যবহারকারীর জন্য আউটপুট

এবার দ্বিতীয় দর্শক: ব্যবহারকারী। তিনি দেখেন শুধু পাতা। পর্ব ০২-এ দেখেছেন, browser HTML পড়ে একটি গাছের মতো কাঠামো বানায় — DOM. JavaScript সেই গাছের যেকোনো ডাল খুঁজে বদলাতে পারে। সবচেয়ে সহজ আর নিরাপদ জোড়াটি হলো:

const banner = document.querySelector('#banner');   // id="banner" উপাদানটি খোঁজো
banner.textContent = 'স্বাগতম, রাফি!';                // তার লেখা বদলাও

document.querySelector একটি CSS selector নেয় (#id, .class, h1…) আর প্রথম মিল পাওয়া উপাদানটি দেয়; কিছু না পেলে দেয় null. textContent উপাদানের ভেতরের লেখা বদলায় — এবং যা দেন তা শুধু লেখা হিসেবেই বসে, HTML হিসেবে নয়। DOM-এর পুরো গল্প পর্ব ৩৭-এ।

  1. app.js চলছেtotal = 814হিসাব মেমরিতে
  2. Consoleconsole.logডেভেলপার দেখেন
  3. DOM-এ খোঁজাquerySelectorউপাদান হাতে নেওয়া
  4. পাতাtextContentব্যবহারকারী দেখেন
  1. হিসাব হলো মেমরিতে। Script চলল, total-এ 814 এলো। এই মুহূর্তে কেউই কিছু দেখছেন না — মান আছে শুধু engine-এর মেমরিতে।
  2. Console — পর্দার আড়ালে। console.log('মোট:', total) লেখাটি পাঠাল DevTools-এ। আপনি F12 খুললে দেখবেন; দোকানের ক্রেতা কখনো দেখবেন না। এটি হিসাব যাচাইয়ের খাতা, রসিদ নয়।
  3. পাতায় লিখতে আগে উপাদান খুঁজুন। document.querySelector('#bill') DOM-গাছে id="bill" খোঁজে। Script যদি HTML-এর আগে চলে, উপাদানটি তখনো তৈরি হয়নি — ফল null, আর পরের লাইনে TypeError. এজন্যই script কোথায় বসাবেন তা জরুরি (নিচে দেখুন)।
  4. রসিদ ছাপা হলো। textContent পাতার লেখা বদলাল; browser সাথে সাথে নতুন করে আঁকল। এবার ব্যবহারকারী দেখছেন “মোট 814 টাকা”। একই মান, ভিন্ন দর্শক, ভিন্ন পথ।

innerHTML — শক্তিশালী, কিন্তু বিপজ্জনক

innerHTML-ও লেখা বসায়, তবে যা দেন তাকে HTML হিসেবে পড়ে। নিজের লেখা নির্দিষ্ট HTML-এর জন্য ঠিক আছে। কিন্তু ব্যবহারকারীর দেওয়া কিছু (নাম, মন্তব্য, URL-এর অংশ) innerHTML-এ ঢোকালে, কেউ নামের জায়গায় HTML ট্যাগ লিখে তার ভেতরে script চালানোর ব্যবস্থা করতে পারে। একে বলে XSS — ওয়েবের সবচেয়ে পরিচিত নিরাপত্তা-ত্রুটিগুলোর একটি।

// ✗ ঝুঁকিপূর্ণ: ব্যবহারকারীর লেখা HTML হিসেবে পড়া হবে
greeting.innerHTML = 'স্বাগতম, ' + userName;

// ✓ নিরাপদ: যা-ই থাকুক, শুধু লেখা হিসেবে দেখাবে
greeting.textContent = 'স্বাগতম, ' + userName;

নিয়মটি সহজ: ব্যবহারকারীর ডেটা মানেই textContent. নিরাপদভাবে HTML বানানোর পূর্ণ কৌশল, আর Content Security Policy — পর্ব ৪৩-এ।

যেগুলো আছে, কিন্তু এড়িয়ে চলবেন

document.write

১৯৯০-এর দশকের পদ্ধতি। পাতা লোড হওয়ার সময় চললে HTML-এর মাঝে লেখা ঢোকায়; কিন্তু লোড শেষে চললে পুরো পাতা মুছে নতুন করে লেখে। ধীর সংযোগে Chrome কিছু ক্ষেত্রে এর মাধ্যমে আসা script আটকেও দেয়। নতুন কোডে কখনো নয়।

বদলে: textContent

alert / prompt / confirm

Browser-এর ছোট পপআপ। পুরো পাতা আটকে রাখে, দেখতে পুরোনো, আর ব্যবহারকারীরা বিরক্ত হন। এই কোর্সের কোড-runner নিরাপদ sandbox-এ চলে, যেখানে এগুলো বন্ধ — তাই আমরা ব্যবহার করব না।

বদলে: পাতার ভেতরে বার্তা বা <dialog>

Script কোথায় বসাবেন

HTML ওপর থেকে নিচে পড়া হয়। <head>-এ সাধারণ <script src> রাখলে script চলে body তৈরির আগেই — তখন querySelector পায় null, আর textContent বসাতে গেলে আসে TypeError: Cannot set properties of null (setting 'textContent') (V8-এর বার্তা, Node-এ যাচাই করা)। পর্ব ০২-এর সমাধানটিই মনে রাখুন:

<head>
  <script src="app.js" defer></script>   <!-- HTML পড়া শেষ হলে চলবে -->
</head>

defer মানে “ফাইলটি এখনই নামাও, কিন্তু চালাও HTML পুরো পড়া শেষ হলে।” type="module" দেওয়া script-ও নিজে থেকে defer-এর মতো আচরণ করে।

৬ · Error পড়তে শিখুন — প্রথম আসল দক্ষতা

প্রোগ্রামিং শেখার প্রথম মাসে আপনি সফল আউটপুটের চেয়ে বেশি error দেখবেন। অভিজ্ঞরাও প্রতিদিন দেখেন — পার্থক্য হলো, তাঁরা মেসেজটি পড়েন, ভয় পান না। JavaScript-এ শুরুতে তিনটি error সবচেয়ে বেশি আসে:

Errorকখন ধরা পড়েসাধারণ কারণযাচাই করা বার্তা (Edge ও Node একই)
SyntaxErrorParsing-এর সময় — একটি লাইনও চলে নাবন্ধনী, উদ্ধৃতিচিহ্ন বা কমা কম-বেশিmissing ) after argument list, Unexpected end of input
ReferenceErrorচলার সময়, সেই লাইনে পৌঁছালেনামের বানান ভুল, ঘোষণা না করা নামcustomerNmae is not defined
TypeErrorচলার সময়, সেই লাইনে পৌঁছালেনাম আছে, কিন্তু মানটি দিয়ে সেই কাজ হয় না — যেমন undefined-কে function হিসেবে ডাকাshop.greet is not a function

“কখন ধরা পড়ে” কলামটি গুরুত্বপূর্ণ। SyntaxError হলে ফাইলের প্রথম লাইনের console.log('Start')-ও ছাপা হয় না — কারণ engine parsing-এই আটকে গেছে (অংশ ১-এর প্রথম ধাপ)। কিন্তু ReferenceError বা TypeError হলে ভুলের আগের লাইনগুলো দিব্যি চলে, ভুলের লাইনে এসে প্রোগ্রাম থামে। দুটোই Edge-এ চালিয়ে মিলিয়ে দেখা। নিচের কোডটি নিজে চালিয়ে দেখুন — এতে একটি বানান ভুল ইচ্ছা করে রাখা:

const customerName = 'Rafi';
console.log('Start');
console.log('Welcome, ' + customerNmae);
console.log('End');

আউটপুটে আসে Start, তারপর লাল লেখায় Uncaught ReferenceError: customerNmae is not defined. End কখনো ছাপা হয় না — error-এর পরে প্রোগ্রাম থেমে গেছে। ঘোষণা করা হয়েছিল customerName, কিন্তু ব্যবহার করা হলো customerNmae (m আর a-র জায়গা বদল)। Engine-এর কাছে এরা সম্পূর্ণ আলাদা দুটি নাম। “Uncaught” মানে কোনো কোড এই error ধরে সামলায়নি — ধরার কৌশল (try/catch) পর্ব ২৯-এ। ঠিক করে আবার চালান: End-ও আসবে।

এই পাতার runner শুধু ধরন আর বার্তা দেখায়। আসল DevTools বা Node আরও বেশি তথ্য দেয় — আর সেখানেই আসল সাহায্য। একই কোড app.js নামে Node-এ চালালে যা আসে, তা অংশ ধরে ধরে পড়ি:

Terminal — node app.jsপুরো মেসেজ
Start
C:\js-course\app.js:3
console.log('Welcome, ' + customerNmae);
                          ^

ReferenceError: customerNmae is not defined
    at Object.<anonymous> (C:\js-course\app.js:3:27)
    at Module._compile (node:internal/modules/cjs/loader…)
    … Node-এর ভেতরের আরও কয়েকটি লাইন …
ধাপ ২ধরন আর বার্তা
Start
C:\js-course\app.js:3
console.log('Welcome, ' + customerNmae);
                          ^

ReferenceError: customerNmae is not defined
    at Object.<anonymous> (C:\js-course\app.js:3:27)
ধাপ ৩ফাইল, লাইন আর ^ চিহ্ন
Start
C:\js-course\app.js:3
console.log('Welcome, ' + customerNmae);
                          ^

ReferenceError: customerNmae is not defined
ধাপ ৪stack — কে কাকে ডেকেছিল
ReferenceError: customerNmae is not defined
    at Object.<anonymous> (C:\js-course\app.js:3:27)   ← আপনার কোড
    at Module._compile (node:internal/…)        ← Node-এর নিজের
    at Module.load (node:internal/…)            ← Node-এর নিজের
Edge DevTools → Consoleএকই ভুল, browser-এর রূপ
Start
Uncaught ReferenceError: customerNmae is not defined
    at app.js:3:27              ← চাপলে Sources-এ সেই লাইন খোলে
  1. পুরো মেসেজ — ভয় না পেয়ে দেখুন। প্রথম লাইনে Start — অর্থাৎ ভুলের আগের লাইন চলেছে। বাকিটা দেখতে লম্বা, কিন্তু এতে মাত্র চারটি তথ্য। (ফোল্ডারের পথ ছোট করে দেখানো; Node-এর ভেতরের লাইনগুলো বাদ।)
  2. ধরন আর বার্তা — “কী হয়েছে”. ReferenceError বলছে সমস্যাটি নামের: এই নামে কিছু খুঁজে পাওয়া যায়নি। বার্তা customerNmae is not defined বলে দিচ্ছে কোন নাম। প্রথম কাজ: এই নামটি কপি করে কোডে খুঁজুন, আর যে নামটি ঘোষণা করেছিলেন তার সাথে অক্ষর ধরে মেলান।
  3. ঠিকানা — “কোথায় হয়েছে”. app.js:3 মানে app.js ফাইলের ৩ নম্বর লাইন। তার নিচে Node সেই লাইনটি হুবহু কপি করে দেয়, আর ^ চিহ্ন দিয়ে দেখায় ঠিক কোন অক্ষরে সমস্যা — এখানে customerNmae-এর শুরুতে।
  4. Stack — “কোন পথে এখানে এলো”. at … লাইনগুলো হলো stack trace. প্রথম লাইনটিই সবচেয়ে জরুরি: app.js:3:27 — লাইন ৩, column ২৭ (বাঁ থেকে ২৭তম অক্ষর)। node:internal লেখা লাইনগুলো Node-এর নিজের কোড; আপাতত উপেক্ষা করুন। বড় প্রোগ্রামে function-এর ভেতর থেকে আরেক function ডাকা হলে এখানে একটি শিকল দেখবেন — পর্ব ০৫-এ call stack দেখার পর এটি পুরো বোঝা যাবে।
  5. Browser-এ একই জিনিস, ভিন্ন সাজ। Edge (এবং Chrome) console-এ সামনে লেখে Uncaught, আর ঠিকানা দেয় app.js:3:27 — নীল লিংক, চাপলেই Sources প্যানেলে সেই লাইনটি খুলে যায়। Engine একই (V8), তাই ধরন আর বার্তা হুবহু এক। Firefox-এর engine আলাদা, তাই কিছু বার্তার ভাষা ভিন্ন হতে পারে — কিন্তু ধরন (ReferenceError ইত্যাদি) সবখানে এক, কারণ সেগুলো ভাষার মানদণ্ডে নির্দিষ্ট।

SyntaxError আর TypeError — Node-এ যেমন দেখায়

C:\js-course\app.js:2
console.log('Total: ' + (45 + 30);
                                ^

SyntaxError: missing ) after argument list

এখানে Start নেই — parsing-এই থেমেছে। console.log(-এর বন্ধনী খোলা হয়েছিল, কিন্তু (45 + 30) বন্ধ হওয়ার পর আরেকটি ) লাগত। খেয়াল করুন, ^ যেখানে, ভুলটি অনেক সময় তার ঠিক আগে — engine যেখানে বুঝল “কিছু মিলছে না”, সেটি দেখায়, যেখানে আপনি ভুল করেছেন সেটি নয়। আর শেষের } হারালে বার্তা আসে SyntaxError: Unexpected end of input — “ফাইল শেষ, অথচ আমি তখনো বন্ধনী খুঁজছিলাম।”

Start
C:\js-course\app.js:3
shop.greet();
     ^

TypeError: shop.greet is not a function
    at Object.<anonymous> (C:\js-course\app.js:3:6)

shop আছে (তাই ReferenceError নয়), কিন্তু তার ভেতরে greet নেই, অর্থাৎ shop.greet-এর মান undefined. আর undefined-কে () দিয়ে ডাকা যায় না। AI-এর লেখা কোডে এটি খুব সাধারণ — এমন method ডাকা, যা আসলে নেই।

ধাপে ধাপে ঠিক করার নিয়ম
  1. প্রথম error-টিই পড়ুন। একটি ভুল থেকে পরের অনেকগুলো জন্মাতে পারে।
  2. ধরন দেখুন: SyntaxError → বন্ধনী/উদ্ধৃতি গুনুন; ReferenceError → নামের বানান মেলান; TypeError → মানটি আসলে কী, console.log দিয়ে দেখুন।
  3. file:line:column-এ যান, আর তার ঠিক আগের লাইনটিও দেখুন।
  4. একটিমাত্র পরিবর্তন করুন, আবার চালান। একসাথে পাঁচটা বদলালে কোনটা কাজ করল বোঝা যায় না।
পরীক্ষা ও ইন্টারভিউতে
  • ReferenceError আর TypeError-এর পার্থক্য? — নামটাই খুঁজে না পেলে ReferenceError; নাম আছে কিন্তু মানটি দিয়ে অসম্ভব কাজ (যেমন undefined ডাকা) করলে TypeError.
  • return-এর পরের লাইনে object লিখলে কী ফেরত আসে? — undefined, কারণ ASI return-এর পরেই ; বসায়।
  • textContent আর innerHTML-এর পার্থক্য? — textContent সবকিছু সাধারণ লেখা হিসেবে বসায়; innerHTML HTML হিসেবে পড়ে, তাই ব্যবহারকারীর ডেটায় XSS-এর ঝুঁকি।
  • "use strict" কী করে? — ঘোষণা না করা নামে মান বসানোর মতো নিঃশব্দ ভুলকে error বানায়; module আর class নিজে থেকেই strict.
  • console.log("2" + 3)-এর আউটপুট? — 23, কারণ একটি string থাকলে + জোড়া দেয়।

৭ · প্রথম ছোট প্রজেক্ট — “আজকের বাজার” বিল ভাগ

এবার সব জোড়া লাগাই। তিন বন্ধু মেসে থাকেন, আজ একজন বাজার করেছেন। প্রোগ্রামটি দাম যোগ করবে, তিনজনে ভাগ করবে, হিসাবের খুঁটিনাটি console-এ রাখবে (আপনার যাচাইয়ের জন্য), আর পরিষ্কার একটি স্বাগত-ব্যানার ও বিল দেখাবে পাতায় (বন্ধুদের জন্য)। ক্রেতার নাম আপাতত কোডেই লেখা — ফর্ম থেকে নাম নেওয়া শিখবেন পর্ব ৩৯-এ। চালিয়ে দেখুন — ওপরে পাতা, নিচে console:

// আজকের বাজার — হিসাব console-এ, ফল পাতায়
const customerName = 'রাফি';
const rice = 320;      // চাল (টাকা)
const lentils = 145;   // ডাল
const oil = 199;       // তেল
const eggs = 150;      // ডিম

const total = rice + lentils + oil + eggs;
const people = 3;
const share = total / people;

console.log('মোট:', total);
console.log('ভাগ (কাঁচা মান):', share);
console.log('ভাগ (toFixed):', share.toFixed(2));

document.querySelector('#banner').textContent = 'স্বাগতম, ' + customerName + '!';
document.querySelector('#bill').textContent =
  'আজকের বাজার ' + total + ' টাকা, ' + people + ' জনে ভাগ করলে জনপ্রতি ' + share.toFixed(2) + ' টাকা';

Console-এ তিন লাইন: মোট: 814, ভাগ (কাঁচা মান): 271.3333333333333 আর ভাগ (toFixed): 271.33. পাতায় বড় অক্ষরে “স্বাগতম, রাফি!” আর নিচে বিলের বাক্য। লক্ষ করুন, কাঁচা মানটি শুধু console-এ — বন্ধুদের সামনে toFixed(2) করা পরিষ্কার সংখ্যা। শেষ statement দুই লাইনে ভাঙা হলেও সমস্যা নেই: =-এর পরে লাইন ভাঙলে engine বোঝে statement শেষ হয়নি, তাই ASI ; বসায় না। একটি পরীক্ষা করুন: '#bill'-কে '#bil' বানিয়ে চালান — কোন error, আর কেন? (উত্তর অনুশীলন ২-এ।)

দুই জায়গায় + দিয়ে লেখা জোড়া দেওয়া একটু ঝামেলার, তাই না? Backtick দিয়ে `জনপ্রতি ${share.toFixed(2)} টাকা` লেখার আরও পরিষ্কার উপায় আছে — template literal, পর্ব ০৯-এ। আর toFixed-এর একটি সূক্ষ্ম ফাঁদ ((1.005).toFixed(2) দেয় "1.00", "1.01" নয়) পর্ব ১০-এ খুলে দেখব।

৮ · AI-এর যুগে — প্রথম প্রোগ্রাম থেকেই যাচাইয়ের অভ্যাস

“একটা JavaScript দিয়ে স্বাগত বার্তা দেখানোর কোড দাও” — AI কয়েক সেকেন্ডে কোড দেবে, আর সেটি চলবেও। কিন্তু ইন্টারনেটের পুরোনো টিউটোরিয়াল থেকে শেখা AI প্রায়ই এমন অভ্যাস নিয়ে আসে, যা এই পর্বে এড়াতে শিখলেন:

AI যা প্রায়ই দেয়সমস্যাযা চাইবেন
el.innerHTML = 'Hi ' + name, যেখানে name ব্যবহারকারীরXSS-এর দরজা খোলাtextContent
document.write(...)পুরোনো; লোডের পরে চললে পুরো পাতা মোছেquerySelector + textContent
সবখানে varপুরোনো scope-নিয়ম, অপ্রত্যাশিত বাগ (পর্ব ০৭)const, দরকার হলে let
alert()/prompt() দিয়ে ইনপুট-আউটপুটপাতা আটকায়, বিরক্তিকর, sandbox-এ বন্ধপাতার ভেতরে উপাদান
<head>-এ defer ছাড়া scriptnull → TypeErrordefer বা type="module"

আরেকটি বড় অভ্যাস: error মেসেজ নিজে আগে পড়ুন। পুরো মেসেজ না পড়েই AI-কে “ঠিক করে দাও” বললে AI প্রায়ই অনুমান করে পুরো কোড নতুন করে লেখে — হয়তো অন্য জায়গায় নতুন ভুলসহ। আপনি যদি আগে বলতে পারেন “ReferenceError, লাইন ৩, নাম customerNmae”, তাহলে অর্ধেক কাজ শেষ — আর AI-এর উত্তর মিলিয়ে দেখার ক্ষমতাও আপনার হাতে।

AI-কে কোড চাইলে শর্তগুলো আগেই বলে দিন, আর ব্যাখ্যা চান। নিচের prompt কপি করে নিজের কাজে বদলে নিন:

আমি JavaScript শিখছি। একটি ছোট browser প্রোগ্রাম লিখে দাও যা ৪টি জিনিসের দাম যোগ করে, ৩ জনে ভাগ করে, আর পাতায় একটি স্বাগত-ব্যানার ও বিল দেখায়। শর্ত: ১. শুধু const/let — var নয়। ২. পাতায় লিখতে querySelector আর textContent — innerHTML বা document.write নয়। ৩. alert/prompt নয়। ৪. টাকা দুই ঘর দশমিকে (toFixed(2)). ৫. script ট্যাগে defer দেখাও। প্রতিটি লাইনের পাশে সহজ বাংলায় comment দাও। শেষে বলো, কোন একটি নাম ভুল বানানে লিখলে কোন error আসবে এবং মেসেজে কী দেখব।

AI-এর কোড হাতে পেলে — যাচাইয়ের চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলোই আপনাকে কোড-লেখক থেকে সিস্টেম-চিন্তক বানাবে।

প্র ০১প্রায় সব ভাষার প্রথম প্রোগ্রাম কেন “Hello, World!”? এই ছোট ঐতিহ্যের পেছনে আসলে কোন প্রকৌশল-বুদ্ধি আছে?

ঐতিহ্যটি এসেছে Bell Labs থেকে। Brian Kernighan ১৯৭২ সালের দিকে B ভাষার একটি অভ্যন্তরীণ টিউটোরিয়ালে “hello, world” ছাপানোর উদাহরণ ব্যবহার করেন বলে ধরা হয়। পরে ১৯৭৮ সালে Kernighan ও Dennis Ritchie-র বই The C Programming Language প্রথম উদাহরণ হিসেবে এটিকে রাখে, আর বইটি এত জনপ্রিয় হয় যে প্রায় সব ভাষার টিউটোরিয়াল এই রীতি নিয়ে নেয়। মূল বইয়ে লেখাটি ছিল ছোট হাতে আর বিস্ময়চিহ্ন ছাড়া — “Hello, World!” রূপটি পরে প্রচলিত হয়েছে।

কিন্তু ঐতিহ্যটি টিকে আছে শুধু আবেগের জন্য নয়। এক লাইনের এই প্রোগ্রাম আসলে একটি পুরো পাইপলাইনের পরীক্ষা। এটি চললে প্রমাণ হয়: editor ফাইল ঠিকমতো সেভ করছে, engine বা compiler ইনস্টল আছে, ফাইলটি ঠিক জায়গা থেকে চালানো হচ্ছে, আর আউটপুট আপনার চোখ পর্যন্ত পৌঁছাচ্ছে। প্রকৌশলে একে বলে smoke test — নতুন যন্ত্র চালু করে দেখা ধোঁয়া বেরোয় কি না। সার্ভার deploy করার পর প্রথমে একটি “health check” পাতা খোলা, বা নতুন bKash ইন্টিগ্রেশনে প্রথমে ১ টাকার লেনদেন করা — একই চিন্তা।

JavaScript-এর ক্ষেত্রে একটি বাড়তি মাত্রা আছে: “Hello, World!” দুই জায়গায় লেখা যায় — console-এ আর পাতায়। দুটো আলাদা পাইপলাইন। Console-এ এলো কিন্তু পাতায় এলো না, মানে engine ঠিক আছে, সমস্যা DOM বা script-এর অবস্থানে। এই ভাগ করে দেখার অভ্যাসটিই পরে বড় বাগ খোঁজার মূল পদ্ধতি হয়ে ওঠে — সমস্যার জায়গাকে অর্ধেক অর্ধেক করে ছোট করা।

মূল উপলব্ধি: সবচেয়ে ছোট যে কাজটি পুরো পথ পার হয়, আগে সেটি চালান। কাজ করলে তারপর জটিলতা বাড়ান — কাজ না করলে জানবেন সমস্যা কোডে নয়, পরিবেশে।

প্র ০২Semicolon দেবেন, নাকি দেবেন না? StandardJS-এর মতো semicolon-ছাড়া স্টাইল আর “সবসময় semicolon” — কোন যুক্তি কতটা শক্ত?

ASI ছিল ১৯৯৫ সালের মূল নকশারই অংশ — উদ্দেশ্য, নতুনদের ছোট ভুল ক্ষমা করা। বহু বছর পরে এটি একটি দীর্ঘ বিতর্কের বিষয় হয়ে দাঁড়ায়। ২০১২ সালে জনপ্রিয় Bootstrap লাইব্রেরির কোডে semicolon না থাকায় Douglas Crockford-এর কোড ছোট করার টুল JSMin সেটি ভেঙে ফেলে; Crockford কোডটিকে দোষ দেন, Bootstrap-এর লেখকেরা টুলটিকে। একদিকে ভাষার নিয়ম, অন্যদিকে টুলের প্রত্যাশা — বিতর্কটি খুব প্রকাশ্য হয়ে ওঠে।

Semicolon-ছাড়া পক্ষের যুক্তি (npm-এর মূল কোড এবং পরে StandardJS এই স্টাইল নেয়): ASI-এর নিয়ম আসলে ছোট ও নির্দিষ্ট — শুধু (, [, `, +, - দিয়ে শুরু হওয়া লাইনে সাবধান থাকলেই হয়। কোড দেখতে পরিষ্কার, টাইপ কম। আর linter এই বিপজ্জনক লাইনগুলো ধরিয়ে দেয়।

সবসময়-semicolon পক্ষের যুক্তি (Google-এর JavaScript style guide, Airbnb, আর Prettier-এর ডিফল্ট): নিয়মের ব্যতিক্রম মনে রাখার চেয়ে কোনো ব্যতিক্রম না থাকা সহজ। C, Java, C# থেকে আসা ডেভেলপারের কাছে স্বাভাবিক। আর ভবিষ্যতে ভাষায় নতুন syntax যোগ হলে ASI-এর আচরণ নতুন ফাঁদ তৈরি করতে পারে — TC39 নিজেও নতুন প্রস্তাব নিয়ে আলোচনায় এই ঝুঁকির কথা তোলে।

লক্ষ করার মতো বিষয় হলো, দুই পক্ষই return-এর ফাঁদ থেকে মুক্ত নয় — semicolon দিলেও return-এর পরে লাইন ভাঙলে undefined-ই আসে। আজকের বাস্তবতা হলো, বেশিরভাগ দল এই সিদ্ধান্ত আর হাতে নেয় না: Prettier-এর মতো formatter সেভ করার সময়ই পুরো কোড একই রূপে সাজিয়ে দেয়। বিতর্কটা তাই অনেকটা “কোন দিকে গাড়ি চলবে” প্রশ্নের মতো — দুই দিকই চলে, শুধু সবাইকে এক দিকে চলতে হবে।

মূল উপলব্ধি: স্টাইলের প্রশ্নে “সঠিক” উত্তরের চেয়ে বড় হলো ধারাবাহিকতা আর স্বয়ংক্রিয়তা। একটি নিয়ম বেছে নিন, টুল দিয়ে সেটি চাপিয়ে দিন, আর মানুষের মনোযোগ রাখুন আসল যুক্তির ভুলের জন্য।

প্র ০৩JavaScript-এ আলাদা compile ধাপ নেই — এর ফলে ভুল ধরা পড়ার সময় কীভাবে বদলায়? Parse error আর runtime error-এর পার্থক্য কেন গুরুত্বপূর্ণ?

C বা Java-তে আপনি আগে compile করেন; ব্যাকরণের ভুল, এমনকি ভুল নামের অনেক সমস্যা, প্রোগ্রাম চালানোর আগেই ধরা পড়ে। JavaScript-এ ফাইলটি সরাসরি engine-এর হাতে যায়। Engine ভেতরে ভেতরে ঠিকই compile করে (আধুনিক engine JIT compiler ব্যবহার করে — পর্ব ০৫-এ দেখবেন), কিন্তু সেটি ঘটে চালানোর মুহূর্তে, আর আপনি আলাদা কোনো ধাপ দেখেন না।

ফলে ভুল দুই স্তরে ধরা পড়ে। Parse error (SyntaxError): ফাইল পড়ার সময়ই ধরা পড়ে, আর পুরো script বাতিল হয় — একটি লাইনও চলে না। এটি একরকম আশীর্বাদ, কারণ ভুল সাথে সাথে চোখে পড়ে। Runtime error (ReferenceError, TypeError): ধরা পড়ে কেবল যখন সেই লাইন সত্যিই চলে। একটি if-এর ভেতরের বানান ভুল, যেটি শুধু বিরল ক্ষেত্রে চলে — মাসের পর মাস লুকিয়ে থাকতে পারে, তারপর হঠাৎ কোনো ব্যবহারকারীর সামনে ফেটে পড়তে পারে।

এই দুর্বলতা ঢাকতেই আধুনিক JavaScript জগতে একগাদা “আগে-ভাগে” টুল তৈরি হয়েছে। ESLint কোড না চালিয়েই ঘোষণা না করা নাম ধরে ফেলে। TypeScript পুরো একটি টাইপ-যাচাইয়ের ধাপ যোগ করে — shop.greet না থাকলে লেখার সময়ই লাল দাগ। আর টেস্ট (পর্ব ৪৮) নিশ্চিত করে যে বিরল পথগুলোও অন্তত একবার চলেছে। অর্থাৎ যে compile ধাপ ভাষায় নেই, পেশাদার দলগুলো সেটি টুল দিয়ে ফিরিয়ে আনে।

উল্টো দিকে সুবিধাও আছে: সেভ করে browser রিফ্রেশ করলেই ফল, মাঝে কোনো অপেক্ষা নেই। এই দ্রুত প্রতিক্রিয়ার কারণেই ওয়েব এত দ্রুত বেড়েছে, আর নতুনরা এত সহজে শুরু করতে পারেন।

মূল উপলব্ধি: “চলেছে” মানে “ঠিক আছে” নয় — মানে শুধু “যে পথগুলো চলেছে, সেগুলোতে ভুল পাওয়া যায়নি।” তাই JavaScript-এ linter, টাইপ আর টেস্ট বিলাসিতা নয়, প্রয়োজন।

প্র ০৪“use strict” একটি সাধারণ string — এমন অদ্ভুত উপায়ে ভাষার ভুল সংশোধন কেন? “Don't break the web” নীতি আসলে কী?

২০০৯ সালের মধ্যে কোটি কোটি ওয়েবপাতা JavaScript-এর পুরোনো আচরণের ওপর দাঁড়িয়ে ছিল — অনেকগুলোর মালিক আর নেই, কেউ আর সেগুলো আপডেট করবে না। ভাষার কোনো আচরণ বদলালে সেই পাতাগুলো রাতারাতি ভেঙে যেত। Browser নির্মাতারা জানেন, কোনো সাইট নতুন সংস্করণে ভাঙলে ব্যবহারকারী দোষ দেন browser-কে, আর অন্য browser-এ চলে যান। তাই ভাষার মানদণ্ড কমিটি (TC39) একটি কঠোর নীতি মানে: “don't break the web” — নতুন সংস্করণে পুরোনো বৈধ কোড আগের মতোই চলতে হবে।

তাহলে পুরোনো ভুল ঠিক হবে কীভাবে? ES5-এর (২০০৯) চতুর সমাধান: opt-in. যে চায়, সে নতুন নিয়ম বেছে নেবে। আর বেছে নেওয়ার সংকেত হিসেবে বেছে নেওয়া হলো একটি string — "use strict";. কেন string? কারণ পুরোনো engine-এর কাছে এটি একটি নিরীহ, অর্থহীন expression; তারা উপেক্ষা করে চালিয়ে যায়। নতুন engine এটি চিনে কঠোর মোড চালু করে। একই ফাইল দুই প্রজন্মের browser-এই চলে — নতুন কোনো keyword হলে পুরোনো browser-এ SyntaxError হতো।

Strict mode কয়েকটি বড় ভুল সংশোধন করে: ঘোষণা না করা নামে মান বসানো error, function-এর ভেতরে this আর আপনাআপনি global object হয় না (পর্ব ২৪), with statement নিষিদ্ধ। ES2015 আরও এক ধাপ এগোয় — module আর class-কে ডিফল্টভাবে strict করে, কারণ সেগুলো নতুন syntax, পুরোনো কোড সেগুলো ব্যবহার করত না।

এই নীতির দাম কখনো কখনো হাস্যকরও হয়। ২০১৮ সালে array-তে flatten নামে একটি method যোগ করার প্রস্তাব এসেছিল, কিন্তু পুরোনো MooTools লাইব্রেরি ব্যবহার করা সাইটগুলো ভেঙে যেত — শেষে নামটাই বদলে flat রাখা হয় (ঘটনাটি “SmooshGate” নামে পরিচিত)। আর typeof null যে "object" দেয়, সেই পরিচিত ভুল আজও আছে — ঠিক করলে অসংখ্য সাইট ভাঙত।

মূল উপলব্ধি: লক্ষ লক্ষ ব্যবহারকারীর সিস্টেমে পুরোনো আচরণ একটি চুক্তি। ভালো প্রকৌশলীরা ভুল সংশোধন করেন পুরোনো চুক্তি না ভেঙে — opt-in, নতুন নাম, বা নতুন syntax দিয়ে। নিজের API বানানোর সময়ও এই শিক্ষা কাজে লাগবে।

প্র ০৫Error message-ও কি একরকম UX? Elm বা Rust-এর বন্ধুসুলভ error-এর পাশে JavaScript engine-এর ছোট মেসেজ কেমন দাঁড়ায়?

Error message হলো একজন বিপদে পড়া মানুষের সাথে প্রোগ্রামের কথোপকথন — তাই এটিও ব্যবহারকারী-অভিজ্ঞতা (UX). এই চিন্তাকে সবচেয়ে জোরালোভাবে সামনে আনে Elm ভাষা। ২০১৫ সালে এর স্রষ্টা Evan Czaplicki “Compiler Errors for Humans” শিরোনামে লেখেন, error কীভাবে বন্ধুর মতো কথা বলতে পারে: সমস্যার জায়গা দেখানো, সাধারণ ভাষায় কারণ বলা, আর সম্ভব হলে সমাধানের ইঙ্গিত — “আপনি কি customerName বোঝাতে চেয়েছিলেন?” এর অনুপ্রেরণায় Rust ২০১৬ সালে তার error-এর নতুন রূপ আনে — রঙিন, কোডের টুকরোসহ, আর প্রায়ই সমাধানের পরামর্শসহ। Rust-কে নতুনদের জন্য কঠিন ভাষা ধরা হলেও তার error message-এর প্রশংসা প্রায় সবাই করেন।

JavaScript engine-এর মেসেজ তুলনায় সংক্ষিপ্ত: customerNmae is not defined — কোনো “আপনি কি … বোঝাতে চেয়েছিলেন?” নেই। এর কারণ আছে। Elm বা Rust-এর compiler পুরো প্রোগ্রাম দেখে, সময় নিয়ে বিশ্লেষণ করতে পারে। JavaScript engine কাজ করে চলার মুহূর্তে, আর তার প্রথম অগ্রাধিকার গতি; তা ছাড়া ভাষাটি এত dynamic যে কোন নাম পরে কোথা থেকে আসবে, আগে নিশ্চিত বলা কঠিন।

তবু উন্নতি হয়েছে। এক সময় Chrome-এ বিখ্যাত বিরক্তিকর মেসেজ ছিল undefined is not a function — কোনটা undefined, বলত না। আজ V8 বলে shop.greet is not a function বা Cannot read properties of undefined (reading 'forEach') — নাম ধরে। আর বাকি সাহায্যের দায়িত্ব নিয়েছে টুল: TypeScript ও ESLint লেখার সময়ই অনেক পরিষ্কার মেসেজ দেয়, আর DevTools-এ লিংকে চাপলেই সরাসরি লাইনটি খুলে যায়।

মূল উপলব্ধি: ভালো error message তিনটি প্রশ্নের উত্তর দেয় — কী হয়েছে, কোথায়, আর কী করা যায়। JavaScript প্রথম দুটি দেয়; তৃতীয়টি আপনার দক্ষতা। আর নিজের প্রোগ্রামের error মেসেজ লেখার সময় (পর্ব ২৯) এই তিন প্রশ্ন মনে রাখুন।

অনুশীলন

বেশিরভাগ কাজ দেখা আর ভাবার — কোডের পরিবর্তন খুব সামান্য।

  1. আউটপুট আগে বলুন: চালানোর আগে লিখে ফেলুন, তারপর console-এ মিলিয়ে দেখুন — (ক) console.log('Total', 45 + 30) (খ) console.log('Total ' + 45 + 30) (গ) console.log(10 / 4)

    (ক) Total 75 — দুটি আলাদা argument; দ্বিতীয়টি আগে হিসাব হয়ে 75.

    (খ) Total 4530 — বাঁ থেকে ডানে: 'Total ' + 45 হয়ে string 'Total 45', তারপর তার সাথে 30 জোড়া। চাইলে 'Total ' + (45 + 30) লিখুন।

    (গ) 2.5 — JavaScript-এ ভাগ পূর্ণসংখ্যায় কাটা হয় না (C বা Java-র int ভাগের মতো নয়)।

  2. Error শিকারি: বাজারের প্রোগ্রামে '#bill'-কে '#bil' বানিয়ে চালালে কোন ধরনের error আসবে? আর customerName-কে শেষ লাইনে customername লিখলে?

    প্রথমটি TypeError — Cannot set properties of null (setting 'textContent'). querySelector('#bil') কিছু পায়নি, তাই দিয়েছে null; আর null-এর ভেতরে লেখা বসানো যায় না। নাম (document, querySelector) সবই ঠিক, সমস্যা মানটিতে — তাই TypeError. Console-এর তিন লাইন কিন্তু আগেই ছাপা হয়ে গেছে।

    দ্বিতীয়টি ReferenceError — customername is not defined, কারণ বড়-ছোট হাতের পার্থক্যে এটি সম্পূর্ণ আলাদা নাম।

  3. ASI গোয়েন্দা: নিচের কোড চালালে কী হবে, ভেবে বলুন — const customer = 'Rafi' (নতুন লাইন) (function () { console.log('hi'); })()

    প্রথম লাইনের শেষে ; নেই, আর পরের লাইন ( দিয়ে শুরু — তাই ASI ; বসায় না। Engine পড়ে 'Rafi'(function () {...})() — অর্থাৎ string 'Rafi'-কে function হিসেবে ডাকার চেষ্টা। ফল TypeError: "Rafi" is not a function (V8-এর বার্তা)। সমাধান: প্রথম লাইনের শেষে ;. এটিই সেই ফাঁদ, যার জন্য semicolon-ছাড়া স্টাইলের লোকেরা এমন লাইনের শুরুতে ; দেন।

  4. নিজের কার্ড বানান (কোড লেখার কাজ): বাজারের প্রোগ্রামটি বদলে একটি “জন্মদিনের কার্ড” বানান — পাতায় একটি শুভেচ্ছা (নাম কোডে লেখা) আর একটি লাইন “কেকের দাম জনপ্রতি … টাকা” (কেক ১২৫০ টাকা, ৭ জনে ভাগ)। Console-এ কাঁচা ভাগফলও দেখান।

    একটি সম্ভাব্য সমাধান (HTML-এ <h2 id="banner"> আর <p id="bill"> থাকতে হবে):

    const friendName = 'Mitu';
    const cakePrice = 1250;
    const people = 7;
    const share = cakePrice / people;
    
    console.log('কাঁচা ভাগ:', share);   // 178.57142857142858
    document.querySelector('#banner').textContent = 'শুভ জন্মদিন, ' + friendName + '!';
    document.querySelector('#bill').textContent =
      'কেকের দাম জনপ্রতি ' + share.toFixed(2) + ' টাকা';

    পাতায় দেখাবে “কেকের দাম জনপ্রতি 178.57 টাকা”। যাচাই করুন: textContent ব্যবহার করেছেন, var নেই, আর হাতে হিসাব করলে 1250 ÷ 7 ≈ 178.57 মেলে।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি JavaScript error ঠিক করার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Console বা terminal-এ প্রথম error মেসেজটি খুঁজে নেওয়া
  2. ধরন পড়া — SyntaxError, ReferenceError না TypeError
  3. file:line:column ধরে কোডের সেই জায়গায় যাওয়া
  4. একটিমাত্র পরিবর্তন করা
  5. আবার চালিয়ে দেখা, error গেল কি না

JavaScript-এ console.log-এর লেখা সাধারণত কে দেখেন?

  • ওয়েবসাইটের সাধারণ ব্যবহারকারী, পাতার ওপরে
  • ডেভেলপার, DevTools-এর console বা terminal-এ
  • সবাই, একটি পপআপ বাক্সে
  • কেউ না, এটি সরাসরি একটি লগ ফাইলে জমা হয়

একটি function-এ return লিখে পরের লাইনে { total: 120 }; লিখলে function কী ফেরত দেয়?

  • { total: 120 }
  • SyntaxError
  • undefined
  • 120

const total = 75; লেখার পর console.log(totl); চালালে কোন error আসে?

  • ReferenceError
  • SyntaxError
  • TypeError
  • কোনো error নয়, undefined ছাপা হয়

একটি ফাইলের প্রথম লাইনে console.log('Start'); আর তৃতীয় লাইনে একটি বন্ধনী কম। চালালে কী দেখা যাবে?

  • Start, তারপর SyntaxError
  • Start, আর engine নিজেই বন্ধনী বসিয়ে বাকিটা চালাবে
  • Start, তারপর ReferenceError
  • শুধু SyntaxError — Start ছাপাই হয় না

ব্যবহারকারীর লেখা একটি নাম পাতায় দেখানোর সবচেয়ে নিরাপদ উপায় কোনটি?

  • element.innerHTML = name
  • element.textContent = name
  • document.write(name)
  • alert(name)

<head>-এর ভেতরে defer ছাড়া রাখা একটি script document.querySelector('#bill').textContent = 'x' চালালে সাধারণত কী হয়?

  • পাতায় ঠিকঠাক 'x' দেখায়
  • ReferenceError: querySelector is not defined
  • TypeError, কারণ querySelector তখন null দেয়
  • Browser নিজে থেকে HTML শেষ হওয়া পর্যন্ত অপেক্ষা করে

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. Engine আগে পুরো ফাইল parse করে, তারপর statement ওপর থেকে নিচে চালায়।
  2. console.log ডেভেলপারের জন্য; পাতায় লিখতে querySelector + textContent.
  3. প্রতিটি statement-এর শেষে ;, আর return-এর মান একই লাইনে — ASI-এর দুই ফাঁদ এড়াতে।
  4. ব্যবহারকারীর ডেটা কখনো innerHTML-এ নয়; document.write আর alert এড়িয়ে চলুন; script-এ defer.
  5. Error পড়ুন: ধরন → বার্তা → file:line:column; প্রথম error আগে, একবারে একটি পরিবর্তন।

পরের পর্বে: আজ দেখলেন engine কোড ওপর থেকে নিচে চালায়। কিন্তু engine-এর ভেতরে আসলে কী ঘটে? V8 কীভাবে আপনার কোডকে machine code বানায় (JIT), আর stack trace-এর সেই at … লাইনগুলো যে call stack থেকে আসে — সেটি কীভাবে কাজ করে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান