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

লিখিত ও মৌখিক (ভাইভা) প্রশ্ন — JavaScript মডেল উত্তর ও কৌশল

Written & Viva Questions in JavaScript — Model Answers, Classic Comparisons, Write-a-Function Problems and How to Speak in an Oral Exam

Taught in Bangla, this page prepares you for written and oral JavaScript exams with 59 written and 36 viva questions and model answers: how examiners mark, a definition-example-limits structure, classic comparisons from == versus === to SSR versus CSR, diagrams of the event loop, prototype chain and CORS preflight, hand-written functions like debounce, deep clone, curry and Promise.all, and using AI as a mock examiner.

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

  • লিখিত উত্তর কোন ক্রমে সাজালে পরীক্ষক সহজে নম্বর দেন — সংজ্ঞা → উদাহরণ → সুবিধা ও সীমা
  • পুরো JavaScript কোর্সের ক্লাসিক তুলনা — ==/=== থেকে SSR/CSR পর্যন্ত — এক জায়গায়
  • event loop, prototype chain, DOM event flow, CORS preflight আর Express middleware চিত্র এঁকে ব্যাখ্যা করা
  • খাতায় বা বোর্ডে লেখার মতো ছোট, সঠিক function — debounce, deep clone, flatten, curry, memoize, groupBy, Promise.all, EventEmitter
  • ভাইভায় গুছিয়ে কথা বলা, নিজের প্রজেক্ট ব্যাখ্যা করা, আর AI-কে পরীক্ষক বানিয়ে তার ভুল ধরা

১ · লিখিত পরীক্ষা ও ভাইভা — পরীক্ষক আসলে কী দেখেন

আগের দুই পর্বে আপনি কোড পড়ে আউটপুট বলেছেন আর MCQ অনুশীলন করেছেন। সেখানে উত্তর হয় ঠিক, নয় ভুল। লিখিত পরীক্ষা আর ভাইভা আলাদা। একই তথ্য জানা দুজন প্রার্থীর একজন বেশি নম্বর পান — কারণ তিনি তথ্যটি গুছিয়ে, উদাহরণসহ আর নিজের ভাষায় বলেছেন।

JavaScript-এর লিখিত প্রশ্ন সাধারণত পাঁচ ধরনের হয়। সংজ্ঞা — “closure কী? উদাহরণসহ লিখুন।” পার্থক্য — “let, const আর var-এর পার্থক্য লিখুন।” চিত্রসহ ব্যাখ্যা — “event loop চিত্রসহ ব্যাখ্যা করুন।” function লিখুন — “একটি debounce function লিখুন।” আর পরিস্থিতি — “একটি search box-এ প্রতিটি অক্ষরে API call যাচ্ছে; কী করবেন?” JavaScript-এ পার্থক্যের প্রশ্ন খুব বেশি আসে, কারণ ভাষাটিতে কাছাকাছি দেখতে অনেক জোড়া আছে: == আর ===, null আর undefined, map আর forEach, call আর bind.

যেকোনো লিখিত উত্তর পড়ার সময় একজন পরীক্ষক মনে মনে চারটি জিনিস খোঁজেন:

নির্ভুল সংজ্ঞা

প্রথম এক–দুই বাক্যে মূল কথা। ভুল বা অস্পষ্ট সংজ্ঞা দিয়ে শুরু হলে বাকি উত্তরের ওপর আস্থা কমে যায়।

শুরু

ছোট সঠিক উদাহরণ

৫–১০ লাইনের কোড, নিচে আউটপুট। আধুনিক JavaScript (const, arrow, ??) লিখলে বোঝা যায় আপনি হালনাগাদ।

উদাহরণ

কীভাবে কাজ করে

engine ভেতরে কী করে — scope chain, microtask queue, prototype lookup. মুখস্থ সংজ্ঞার বাইরে যা বলবেন, সেটাই বোঝার প্রমাণ।

ব্যাখ্যা

সুবিধা, সীমা, কখন কোনটি

খরচ, ফাঁদ আর বিকল্প — এই অংশটি সাধারণ উত্তরকে ভালো উত্তরে নেয়।

উপসংহার

এই পাতার প্রশ্নগুলো কোর্সের মডিউল অনুযায়ী সাজানো। কোনো অংশে বারবার আটকালে টেবিলের পর্বগুলো আবার পড়ুন:

কোর্সের মডিউলপর্বলিখিত প্রশ্নভাইভা প্রশ্ন
১–২ · ভিত্তি ও মূল ভাষা০১–১৩অংশ ৩ (ক-০১–ক-১১)ভ-০১–ভ-০৬
৩ · ডেটা স্ট্রাকচার১৪–২১অংশ ৪ (খ-০১–খ-০৯)ভ-০৭–ভ-১০
৪ · function ও object গভীরে২২–৩০অংশ ৫ (গ-০১–গ-১০)ভ-১১–ভ-১৫
৫ · Asynchronous JavaScript৩১–৩৬অংশ ৬ (ঘ-০১–ঘ-০৮)ভ-১৬–ভ-১৯
৬ · ব্রাউজার ও DOM৩৭–৪৪অংশ ৭ (ঙ-০১–ঙ-০৯)ভ-২০–ভ-২৩
৭ · পেশাদার JavaScript ও প্রজেক্ট৪৫–৫৫অংশ ৮ (চ-০১–চ-১২)ভ-২৪–ভ-২৮
ভাইভা ও HR-ধাঁচের প্রশ্ন২১, ৫৫—এই-০১–এই-০৮

এই পাতার কোনো প্রশ্ন কোনো নির্দিষ্ট পরীক্ষার প্রশ্নপত্র বা কোনো প্রতিষ্ঠানের ইন্টারভিউ থেকে নেওয়া নয়। এগুলো এমন ধরনের প্রশ্ন, যা বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় প্রায়ই আসে। সিলেবাস, নম্বর বণ্টন আর সময় সবসময় নিজের পরীক্ষার সর্বশেষ বিজ্ঞপ্তি থেকে মিলিয়ে নিন। js লেখা প্রোগ্রাম চলে এই পাতার ভেতরে, ব্রাউজারে; node লেখাগুলো চলে Node.js 20-এ। যেখানে আউটপুট পরিবেশের ওপর নির্ভর করে (ব্রাউজার বনাম Node, strict বনাম sloppy mode), সেখানে তা আলাদা করে বলা আছে।

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

উত্তর সাজানোর কাঠামো সব ভাষায় এক — সংজ্ঞা, উদাহরণ, ব্যাখ্যা, টেবিল, উপসংহার। পার্থক্য প্রশ্নের বিষয়ে: Java-তে যেখানে thread আর synchronized, JavaScript-এ সেখানে event loop আর Promise; C-তে যেখানে pointer, JavaScript-এ সেখানে reference আর closure; Python-এ যেখানে GIL, JavaScript-এ সেখানে single thread আর Web Worker. অন্য ভাষার প্রশ্নব্যাংক: Java, Python, C++, C.

২ · উত্তরের কাঠামো — সংজ্ঞা, উদাহরণ, সুবিধা ও সীমা

প্রায় যেকোনো “ব্যাখ্যা করুন” প্রশ্নের জন্য একটি কাঠামো কাজ করে। একে একটি দালানের মতো ভাবুন — সংজ্ঞা হলো ভিত, উদাহরণ দেয়াল, ব্যাখ্যা আর চিত্র জানালা-দরজা, সুবিধা-সীমা ছাদ।

সংজ্ঞা → উদাহরণ (কোড + আউটপুট) → কীভাবে কাজ করে → সুবিধা ও সীমা → উপসংহার

পাঁচ ধরনের প্রশ্নে পাঁচ রকম উত্তর

প্রশ্নের ধরনযা অবশ্যই থাকবেসাধারণ ভুল
সংজ্ঞা (“X কী?”)এক–দুই বাক্যের সংজ্ঞা, ছোট কোড, কেন দরকার, একটি সীমাশুধু পূর্ণ নাম — “DOM = Document Object Model”
পার্থক্য (“X বনাম Y”)দুটির এক লাইনের সংজ্ঞা, একই মাপকাঠিতে ৫–৭ সারির টেবিল, দুই পাশের উদাহরণ, কখন কোনটিশুধু X নিয়ে লম্বা লেখা; বা মাপকাঠি না মেলানো সারি
চিত্রসহ ব্যাখ্যালেবেল দেওয়া বাক্স-তীর চিত্র, তার নিচে ধাপের তালিকা, একটি ছোট কোড যার আউটপুট চিত্র দিয়ে ব্যাখ্যা হয়সুন্দর ছবি, কিন্তু কোন তীর কী বোঝায় লেখা নেই
function লিখুনএক লাইনে পদ্ধতি, সম্পূর্ণ কোড, নমুনা ইনপুট-আউটপুট, edge case, time complexityঅর্ধেক কোড; this বা আর্গুমেন্ট হারিয়ে যাওয়া; কোনো আউটপুট নেই
পরিস্থিতিসমস্যার কারণ, একটি সমাধান, তার খরচ, একটি বিকল্পপ্রথম মাথায় আসা টুলের নাম বলে থেমে যাওয়া

সবচেয়ে বেশি আসা ধরনগুলোর একটি “উদাহরণসহ ব্যাখ্যা করুন”। ধরা যাক প্রশ্নটি “closure কী? উদাহরণসহ লিখুন” (৫ নম্বর)। নিচের ডায়াগ্রামে “পরে” চাপুন — প্রতিটি ধাপে উত্তরপত্রে একটি নতুন অংশ যোগ হবে।

  1. সংজ্ঞাদুই বাক্য
  2. উদাহরণকোড + আউটপুট
  3. কীভাবেscope chain চিত্র
  4. সুবিধা ও সীমাব্যবহার, ফাঁদ
  5. উপসংহারএক লাইন
উত্তরপত্রধাপ ১ — সংজ্ঞা
Closure: একটি function আর যে পরিবেশে (lexical environment)
সে তৈরি হয়েছিল তার variable-গুলোর সংযোগ — একসাথে।
ফলে বাইরের function শেষ হয়ে গেলেও ভেতরের function
সেই variable পড়তে ও বদলাতে পারে।
উত্তরপত্রধাপ ২ — উদাহরণ যোগ হলো
… (সংজ্ঞা) …
function makeCounter() {
  let count = 0;
  return () => ++count;
}
const next = makeCounter();
next(); next();
console.log(next());   // আউটপুট: 3
উত্তরপত্রধাপ ৩ — কীভাবে কাজ করে
… (সংজ্ঞা, উদাহরণ) …
next ──► [arrow function]
              │ [[Environment]]
              ▼
     makeCounter-এর env { count: 3 }
              │ outer
              ▼
     global env { makeCounter, next }
makeCounter শেষ হলেও env-টি GC হয় না, কারণ next তাকে ধরে আছে।
উত্তরপত্রধাপ ৪ — সুবিধা ও সীমা
… (সংজ্ঞা, উদাহরণ, চিত্র) …
সুবিধা: private state (count বাইরে থেকে ছোঁয়া যায় না),
  function factory, memoization-এর cache, debounce-এর timer.
সীমা: ধরে রাখা variable মেমরিতে থেকে যায় — বড় ডেটা
  ধরে রাখলে memory leak; লুপে var দিলে সব callback
  একই variable দেখে (3 3 3).
উত্তরপত্রধাপ ৫ — সম্পূর্ণ উত্তর
… (সংজ্ঞা, উদাহরণ, চিত্র, সুবিধা ও সীমা) …
উপসংহার: closure কোনো আলাদা syntax নয় — JavaScript-এ
প্রতিটি function-ই তার জন্মস্থানের scope মনে রাখে।
এটাই private data, callback আর async কোডের ভিত্তি।
  1. ধাপ ১ — সংজ্ঞা। দুই বাক্যে মূল কথা: “function + তার জন্মস্থানের variable”. সাথে সবচেয়ে গুরুত্বপূর্ণ ফল — বাইরের function শেষ হলেও variable বেঁচে থাকে। এই এক বাক্যেই পরীক্ষক বোঝেন আপনি জানেন।
  2. ধাপ ২ — উদাহরণ। সবচেয়ে ছোট, সবচেয়ে পরিচিত উদাহরণ — counter. নিচে আউটপুট লিখুন। আউটপুট দেখায় আপনি মনে মনে কোডটি চালিয়েছেন।
  3. ধাপ ৩ — কীভাবে কাজ করে। তিন বাক্সের ছোট চিত্র: function → তার environment → global. [[Environment]] বা “scope chain” শব্দটি ব্যবহার করলে উত্তর বইয়ের মানে ওঠে।
  4. ধাপ ৪ — সুবিধা ও সীমা। কোথায় কাজে লাগে (তিন–চারটি নাম) আর কোথায় বিপদ (memory, লুপের var). এই অংশটিই সাধারণ আর ভালো উত্তরের পার্থক্য।
  5. ধাপ ৫ — উপসংহার। এক–দুই বাক্যে বড় ছবিটা। এখন উত্তরটি সম্পূর্ণ: পাঁচটি অংশ, কোনো নম্বর-ভাগে ফাঁক নেই।
একটি সম্ভাব্য সময়-ভাগ (আমাদের পরামর্শ)

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

খাতায় বা বোর্ডে JavaScript লেখার ছয় নিয়ম

  1. আধুনিক syntax: const ডিফল্ট, বদলাতে হলে let; var শুধু তুলনা দেখাতে। === ডিফল্ট।
  2. function-এর চুক্তি আগে: এক লাইনে লিখুন কী নেয়, কী ফেরত দেয় — “debounce(fn, wait) একটি নতুন function ফেরত দেয়”।
  3. this আর আর্গুমেন্ট হারাবেন না: wrapper function লিখলে (...args) নিন আর fn.apply(this, args) দিয়ে ডাকুন — debounce, memoize, once সবখানে এই নিয়ম।
  4. অর্থবহ নাম: cart, total, timer — a, x নয়।
  5. আউটপুট লিখুন: কোডের নিচে “আউটপুট: …”. async কোডে ক্রমটিও লিখুন।
  6. Edge case এক লাইনে: খালি array, null/undefined, circular reference, খালি Promise তালিকা — কোডে না রাখলেও উল্লেখ করুন।

৩ · অংশ ক — ভিত্তি ও মূল ভাষা (মডিউল ১–২)

রিভিশনের জন্য: পর্ব ০১, পর্ব ০২, পর্ব ০৫, পর্ব ০৬, পর্ব ০৭, পর্ব ০৮, পর্ব ০৯, পর্ব ১০, পর্ব ১১, পর্ব ১২, পর্ব ১৩.

প্রতিটি প্রশ্ন পড়ে আগে নিজে খাতায় উত্তর লিখুন, তারপর প্রশ্নে চেপে মেলান। মডেল উত্তরগুলো সংক্ষিপ্ত কিন্তু সম্পূর্ণ — বড় প্রশ্নে অংশ ২-এর কাঠামো মেনে চিত্র ও কোড যোগ করুন।

ক-০১JavaScript কী? এটি কি interpreted ভাষা, নাকি compiled? (সহজ)

সংজ্ঞা: JavaScript একটি high-level, dynamically typed, garbage-collected ভাষা, যার মান ঠিক করে ECMAScript নির্দেশিকা (TC39 কমিটি প্রতি বছর নতুন সংস্করণ দেয় — ES2015, ES2016 …)। ১৯৯৫ সালে Netscape-এ Brendan Eich এটি বানান। আজ এটি ব্রাউজারে (পাতাকে interactive করতে) আর সার্ভারে (Node.js, ২০০৯ থেকে) দুই জায়গাতেই চলে।

Interpreted না compiled? ভাষা নিজে কোনোটিই নয় — এটা নির্ভর করে engine-এর ওপর। আধুনিক engine (Chrome ও Node-এ V8, Firefox-এ SpiderMonkey, Safari-তে JavaScriptCore) প্রথমে কোড parse করে bytecode বানায়, interpreter দিয়ে চালানো শুরু করে, আর যে function বারবার চলে তাকে JIT compiler দিয়ে machine code-এ রূপান্তর করে। তাই সঠিক উত্তর: “JIT-compiled — interpreter আর compiler দুটোই কাজ করে।”

সীমা যোগ করুন: JIT অনুমানের ওপর চলে (যেমন “এই variable সবসময় number”); অনুমান ভাঙলে deoptimization হয়। তাই একই জায়গায় একই টাইপের মান রাখা পারফরম্যান্সে সাহায্য করে।

ঝালিয়ে নিন: পর্ব ০১, পর্ব ০৫ · engine, JIT আর call stack

ক-০২Call stack আর heap কী? stack overflow কখন হয়? (মাঝারি)

Call stack: কোন function এখন চলছে আর শেষ হলে কোথায় ফিরতে হবে, তার তালিকা। প্রতিটি function call-এ একটি frame উপরে চাপে (local variable, ফেরার ঠিকানা), শেষ হলে সরে যায় — শেষে-ঢোকা-আগে-বের (LIFO). JavaScript-এর main thread-এ stack একটিই, তাই একসাথে একটিই কাজ চলে।

Heap: object, array, function-এর মতো মান যেখানে থাকে — বড়, এলোমেলো মেমরি এলাকা। Stack-এ থাকে শুধু সেগুলোর reference. কেউ আর ধরে না থাকা object garbage collector সরিয়ে দেয়।

Stack overflow: শেষ না হওয়া recursion-এ frame জমতেই থাকে। V8-এ তখন ছোড়া হয় RangeError: Maximum call stack size exceeded. সমাধান: base case ঠিক করা, বা গভীর recursion-কে লুপে বা নিজের stack (array) দিয়ে লেখা। JavaScript-এর মানদণ্ডে proper tail call আছে, কিন্তু V8 তা বাস্তবায়ন করে না — তাই tail recursion-এর ওপর ভরসা করবেন না।

ঝালিয়ে নিন: পর্ব ০৫, পর্ব ১৩

ক-০৩JavaScript-এর ডেটা টাইপগুলো লিখুন। primitive আর object-এর পার্থক্য কী? (সহজ)

মোট আটটি টাইপ। সাতটি primitive: string, number, bigint, boolean, undefined, null, symbol. আর একটি object — array, function, Date, Map সবই এর ভেতরে।

বিষয়primitiveobject
বদলানো যায়?না — immutable; নতুন মান তৈরি হয়হ্যাঁ — property যোগ, বদল, মোছা
variable-এ কী থাকেমানটি নিজেheap-এ রাখা object-এর reference
কপি করলেআলাদা মানএকই object-এ দুটি reference
তুলনা (===)মান দিয়েপরিচয় দিয়ে — একই object কি না
typeof'string', 'number' … (ব্যতিক্রম: null → 'object')'object', function হলে 'function'

উদাহরণ: {a: 1} === {a: 1} হলো false — দুটি আলাদা object. কিন্তু 'চা' === 'চা' হলো true.

ঝালিয়ে নিন: পর্ব ০৬ · মান, টাইপ আর coercion

ক-০৪== আর ===-এর পার্থক্য উদাহরণসহ লিখুন। Object.is কোথায় আলাদা? (সহজ)

সংজ্ঞা: === (strict equality) টাইপ না মিললেই false — কোনো রূপান্তর নেই। == (loose equality) টাইপ আলাদা হলে আগে একটি জটিল নিয়মে coercion করে (সাধারণত number-এর দিকে), তারপর তুলনা করে। Object.is প্রায় ===, শুধু দুই জায়গায় আলাদা: NaN-কে নিজের সমান ধরে, আর 0 ও -0-কে আলাদা ধরে।

const show = v => typeof v === 'string' ? `'${v}'` : Array.isArray(v) ? `[${v}]` : String(v);
const pairs = [[0, ''], [0, '0'], ['', '0'], [null, undefined], [null, 0], [NaN, NaN], [[1], 1], [true, '1']];
for (const [a, b] of pairs) {
  console.log(`${show(a)} == ${show(b)} → ${a == b} | === → ${a === b}`);
}
console.log('Object.is:', Object.is(NaN, NaN), Object.is(0, -0));

আউটপুটে 0 == '' আর 0 == '0' দুটোই true, কিন্তু '' == '0' false — অর্থাৎ == transitive নয়, খাতায় এটি লিখলে উত্তর জোরালো হয়। null == undefined true, অথচ null == 0 false: null শুধু undefined-এর সাথে loosely সমান। NaN কোনো কিছুর সমান নয়, নিজেরও নয় — তাই চেনার উপায় Number.isNaN(x). [1] == 1 true, কারণ array আগে '1' string-এ, তারপর number-এ রূপান্তরিত হয়। শেষ লাইন: true false.

উপসংহার: সবসময় ===; একমাত্র প্রচলিত ব্যতিক্রম x == null, যা একসাথে null আর undefined ধরে। ESLint-এর eqeqeq নিয়ম === বাধ্যতামূলক করে (চাইলে null-এর এই ব্যতিক্রমটি রাখা যায়)।

ঝালিয়ে নিন: পর্ব ০৬, পর্ব ০৮

ক-০৫let, const আর var-এর পার্থক্য লিখুন। hoisting আর TDZ কী? (মাঝারি)
বিষয়varletconst
scopefunction scopeblock scope { }block scope
ঘোষণার আগে পড়লেundefinedReferenceError (TDZ)ReferenceError (TDZ)
আবার ঘোষণা (একই scope)চলেSyntaxErrorSyntaxError
নতুন মান দেওয়াচলেচলেTypeError: Assignment to constant variable.
global-এ ঘোষণা করলে (classic script)window-এর property হয়হয় নাহয় না
লুপে প্রতি পুনরাবৃত্তিতে নতুন bindingনাহ্যাঁহ্যাঁ (for…of-এ)

Hoisting: কোড চালানোর আগে engine প্রতিটি scope-এর সব ঘোষণা নিবন্ধন করে নেয়। var-কে সাথে সাথে undefined দিয়ে শুরু করে; function declaration পুরোটাই তৈরি হয়ে যায় (তাই ঘোষণার আগেই ডাকা যায়)। let/const/class-ও নিবন্ধিত হয়, কিন্তু ঘোষণার লাইন পর্যন্ত শুরু হয় না — সেই অংশটির নাম TDZ (temporal dead zone). TDZ-এ পড়লে V8-এর বার্তা: ReferenceError: Cannot access 'x' before initialization.

সতর্কতা: const মানে binding স্থির, object নয় — const cart = []; cart.push(1) বৈধ। object-ই আটকাতে Object.freeze (তাও শুধু উপরের স্তর)। উপসংহার: const ডিফল্ট, বদলাতে হলে let, নতুন কোডে var নয়।

ঝালিয়ে নিন: পর্ব ০৭ · scope, hoisting আর TDZ

ক-০৬null আর undefined-এর পার্থক্য কী? typeof null কেন 'object'? (মাঝারি)

undefined মানে “মান এখনো দেওয়া হয়নি” — engine নিজে দেয়: ঘোষিত কিন্তু মানহীন variable, না থাকা property, return ছাড়া function, না পাঠানো parameter. null মানে “ইচ্ছা করে খালি” — প্রোগ্রামার নিজে দেন। typeof undefined → 'undefined', typeof null → 'object'. JSON-এ null আছে, undefined নেই — JSON.stringify এমন property বাদ দেয়। default parameter শুধু undefined-এ কাজ করে, null-এ নয়।

typeof null-এর ইতিহাস: প্রথম বাস্তবায়নে মানের সাথে একটি ছোট type tag থাকত, আর object-এর tag ছিল 0; null উপস্থাপন করা হতো শূন্য pointer দিয়ে, তাই তার tag-ও 0 পড়ত। এটি একটি ভুল, কিন্তু ঠিক করলে পুরোনো ওয়েবসাইট ভেঙে যেত — পরে এমন একটি প্রস্তাব বাতিলও হয়েছে। তাই object চেনার নিরাপদ পরীক্ষা: x !== null && typeof x === 'object'.

ঝালিয়ে নিন: পর্ব ০৬

ক-০৭0.1 + 0.2 === 0.3 কেন false? টাকার হিসাব কীভাবে করবেন? BigInt কখন লাগে? (মাঝারি)

JavaScript-এর number হলো IEEE 754 64-bit floating-point. 0.1 বা 0.2 বাইনারিতে ঠিকঠাক লেখা যায় না (যেমন দশমিকে ১/৩), তাই যোগফল 0.30000000000000004. তুলনায় Math.abs(a - b) < Number.EPSILON ধরনের সহনসীমা ব্যবহার করুন।

টাকা: পয়সায় পূর্ণসংখ্যা রাখুন (১২০.৫০ টাকা = 12050 পয়সা), দেখানোর সময় ভাগ করুন আর Intl.NumberFormat দিয়ে ফরম্যাট করুন — পর্ব ২১-এর খরচের খাতা ঠিক এভাবেই বানানো। toFixed দেখানোর জন্য, হিসাবের জন্য নয়।

BigInt: number নিরাপদে পূর্ণসংখ্যা রাখতে পারে শুধু Number.MAX_SAFE_INTEGER = 253 − 1 পর্যন্ত (9007199254740991). এর বাইরে — বড় ID, ক্রিপ্টোগ্রাফি, বড় factorial — 123n আকারের BigInt (ES2020). সীমা: number-এর সাথে সরাসরি মেশানো যায় না (1n + 1 → TypeError), আর JSON.stringify BigInt পেলে TypeError: Do not know how to serialize a BigInt ছোড়ে।

ঝালিয়ে নিন: পর্ব ১০ · number, floating-point আর BigInt

ক-০৮truthy/falsy কী? || আর ??-এর পার্থক্য উদাহরণসহ লিখুন। ?. কী করে? (সহজ)

boolean দরকার এমন জায়গায় (if, &&, ||) প্রতিটি মান truthy বা falsy ধরা হয়। falsy মান মাত্র কয়েকটি: false, 0, -0, 0n, '', null, undefined, NaN. বাকি সব truthy — '0', [], {}-ও।

a || b বাঁ দিক falsy হলেই b দেয়; a ?? b (nullish coalescing, ES2020) শুধু null বা undefined হলে। উদাহরণ: const qty = input || 1; ব্যবহারকারী 0 দিলেও 1 করে দেয় — বাগ। input ?? 1 0 রাখে।

?. (optional chaining): user?.address?.city — মাঝের কোনোটি null/undefined হলে error না ছুড়ে পুরো expression undefined দেয়। method-এও চলে: obj.save?.(). সীমা: অতিরিক্ত ব্যবহার আসল বাগ লুকিয়ে ফেলে — যে মান থাকতেই হবে, সেখানে ?. দেবেন না।

ঝালিয়ে নিন: পর্ব ০৮

ক-০৯function declaration, function expression আর arrow function-এর পার্থক্য লিখুন। (মাঝারি)
বিষয়declarationexpressionarrow
রূপfunction f() {}const f = function () {}const f = () => {}
ঘোষণার আগে ডাকাযায় (পুরো hoisted)যায় নাযায় না
নিজের thisআছে (ডাকার ধরন ঠিক করে)আছেনেই — বাইরের this নেয়
argumentsআছেআছেনেই (rest ...args নিন)
new দিয়ে ডাকাযায়যায়TypeError: f is not a constructor

কখন কোনটি: callback আর ছোট function-এ arrow (বিশেষ করে method-এর ভেতরে, যেখানে বাইরের this দরকার)। object-এর method বা event handler, যেখানে নিজের this দরকার, সেখানে arrow নয়। ES2015-এ arrow, default parameter আর rest parameter এসেছে।

ঝালিয়ে নিন: পর্ব ১৩ · function, পর্ব ২৪ · this

ক-১০for…of আর for…in-এর পার্থক্য কী? array-তে for…in কেন এড়াবেন? (সহজ)

for…of (ES2015) যেকোনো iterable-এর মান দেয় — array, string, Map, Set, generator. for…in একটি object-এর enumerable property-র নাম (string key) দেয় — prototype chain থেকে আসা enumerable property-সহ। array-তে for…in সূচক দেয় string হিসেবে ('0', '1'), কেউ Array.prototype-এ কিছু যোগ করলে সেটিও আসতে পারে, আর ক্রমের ওপর ভরসা করা ঠিক নয়। তাই array-তে for…of বা array method; object-এ Object.entries(obj)-এর ওপর for…of.

ঝালিয়ে নিন: পর্ব ১২ · লুপ

ক-১১JavaScript string immutable — এর মানে কী? 'বাংলা'.length কেন 5? (মাঝারি)

immutable মানে string তৈরি হওয়ার পর তার কোনো অক্ষর বদলানো যায় না; toUpperCase, replace, slice সবাই নতুন string ফেরত দেয়। s[0] = 'x' sloppy mode-এ চুপচাপ উপেক্ষিত হয়, strict mode-এ TypeError.

length গোনে UTF-16 code unit, মানুষের চোখে দেখা অক্ষর নয়। “বাংলা” = ব + া + ং + ল + া — পাঁচটি code point, প্রতিটি একটি code unit, তাই 5. চোখে দেখা অক্ষর (grapheme cluster) গুনতে Intl.Segmenter: “বাংলা”-তে তা 2 (বাং + লা)। emoji-তে আরও পার্থক্য — '😀'.length 2, কারণ এটি একটি surrogate pair. উপসংহার: ইনপুটের দৈর্ঘ্য সীমা, কার্সর বা কাটাকাটিতে length নয়, grapheme ধরে হিসাব করুন।

ঝালিয়ে নিন: পর্ব ০৯ · string আর বাংলা Unicode

৪ · অংশ খ — ডেটা স্ট্রাকচার (মডিউল ৩)

রিভিশনের জন্য: পর্ব ১৪, পর্ব ১৫, পর্ব ১৬, পর্ব ১৭, পর্ব ১৮, পর্ব ১৯, পর্ব ২০, পর্ব ২১.

খ-০১JavaScript কি pass-by-value নাকি pass-by-reference? উদাহরণসহ ব্যাখ্যা করুন। (মাঝারি)

উত্তর: সবসময় pass-by-value — কিন্তু object-এর ক্ষেত্রে যে “মান” কপি হয় তা হলো reference. একে বলে pass-by-sharing. ফলে function-এর ভেতরে object-এর property বদলালে বাইরে দেখা যায়, কিন্তু parameter-কে নতুন object দিলে বাইরের variable বদলায় না।

function addItem(cart) { cart.push('চা'); }          // একই object বদলায়
function reset(cart)   { cart = []; }                // শুধু local কপি বদলায়
const myCart = [];
addItem(myCart); reset(myCart);
console.log(myCart);   // আউটপুট: [ 'চা' ]

উপসংহার: C++-এর & reference-এর মতো আসল pass-by-reference JavaScript-এ নেই। ভেতরে object বদলানো (mutation) বাগের বড় উৎস — তাই নতুন object ফেরত দেওয়া (immutable update) ভালো অভ্যাস।

ঝালিয়ে নিন: পর্ব ১৪ · object আর reference

খ-০২shallow copy আর deep copy-র পার্থক্য লিখুন। circular reference সামলাতে পারে এমন একটি deepClone function লিখুন। (কঠিন)

সংজ্ঞা: shallow copy ({...obj}, Object.assign, [...arr], arr.slice()) শুধু উপরের স্তরের property কপি করে; ভেতরের object আগের মতোই ভাগ করা থাকে। deep copy প্রতিটি স্তর আলাদা করে কপি করে। পদ্ধতি: primitive হলে যেমন আছে ফেরত; object হলে নতুন খালি object বা array বানাই, প্রতিটি property-র ওপর নিজেকে আবার ডাকি (recursion). আগে দেখা object একটি WeakMap-এ মনে রাখি — তাতে circular reference-এ অসীম recursion হয় না, আর একই object দুই জায়গায় থাকলে কপিতেও একটিই থাকে।

function deepClone(value, seen = new WeakMap()) {
  if (value === null || typeof value !== 'object') return value; // primitive
  if (seen.has(value)) return seen.get(value);                     // circular
  if (value instanceof Date) return new Date(value.getTime());
  if (value instanceof Map) {
    const m = new Map();
    seen.set(value, m);
    for (const [k, v] of value) m.set(deepClone(k, seen), deepClone(v, seen));
    return m;
  }
  const copy = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
  seen.set(value, copy);
  for (const key of Object.keys(value)) copy[key] = deepClone(value[key], seen);
  return copy;
}

const order = { id: 7, items: [{ name: 'চা', qty: 2 }], at: new Date(0) };
order.self = order;                       // নিজের দিকেই reference
const c = deepClone(order);
c.items[0].qty = 5;
console.log(order.items[0].qty, c.items[0].qty);
console.log(c.self === c, c.at instanceof Date, c.at !== order.at);

const shallow = { ...order };
console.log(shallow.items === order.items);
const s = structuredClone(order);
console.log(s.self === s, s.items[0].qty);

আউটপুট চার লাইন: 2 5 — কপির ভেতরের object বদলালেও আসলটি অক্ষত; true true true — কপির self কপিকেই দেখায়, Date আলাদা Date object; true — spread করা shallow কপির items আসলটির সাথে একই array; true 2 — built-in structuredClone-ও circular reference সামলায়। সীমা লিখুন: আমাদের function Set, class-এর #private field, symbol key আর getter কপি করে না। বাস্তবে আগে structuredClone ব্যবহার করুন (সব আধুনিক ব্রাউজার আর Node 17+), তবে মনে রাখুন এটি function কপি করতে পারে না (DataCloneError) আর class instance-এর prototype হারায়। JSON.parse(JSON.stringify(x)) সবচেয়ে দুর্বল — Date string হয়ে যায়, undefined আর function হারায়, circular-এ TypeError. সময় ও মেমরি O(n), n = মোট মানের সংখ্যা।

ঝালিয়ে নিন: পর্ব ১৪, পর্ব ১৭, পর্ব ১৯ · structuredClone

খ-০৩map, filter, reduce আর forEach-এর পার্থক্য লিখুন। (সহজ)
methodকী ফেরত দেয়কাজউদাহরণ
mapএকই দৈর্ঘ্যের নতুন arrayপ্রতিটি উপাদান রূপান্তরদাম → ভ্যাটসহ দাম
filterনতুন array (কম বা সমান)শর্ত মেলা উপাদান রাখাস্টকে আছে এমন পণ্য
reduceএকটি মান (যেকোনো টাইপ)সব উপাদান জুড়ে একটি ফলকার্টের মোট দাম
forEachundefinedশুধু side effectপ্রতিটি লাইন DOM-এ লেখা

প্রথম তিনটি মূল array বদলায় না, তাই chain করা যায়: items.filter(i => i.inStock).map(i => i.price).reduce((s, p) => s + p, 0). reduce-এ সবসময় initial value দিন — খালি array-তে initial value ছাড়া TypeError: Reduce of empty array with no initial value. forEach-এর ভেতরে break চলে না আর await করলে অপেক্ষা হয় না — সেখানে for…of.

ঝালিয়ে নিন: পর্ব ১৬ · map, filter, reduce

খ-০৪[10, 1, 2].sort() কেন [1, 10, 2] দেয়? সঠিকভাবে সাজাবেন কীভাবে? (মাঝারি)

comparator না দিলে sort প্রতিটি উপাদানকে string-এ রূপান্তর করে UTF-16 code unit-এর ক্রমে সাজায় — '10' আসে '2'-এর আগে, কারণ প্রথম অক্ষর '1' < '2'. সংখ্যায় সাজাতে comparator দিন: arr.sort((a, b) => a - b) — ঋণাত্মক ফল মানে a আগে। বাংলা নাম সাজাতে a.localeCompare(b, 'bn') বা Intl.Collator.

আরও দুটি কথা লিখুন: sort মূল array বদলায় (in-place) — না বদলাতে চাইলে ES2023-এর toSorted. আর ES2019 থেকে sort stable — সমান উপাদানের আগের ক্রম বজায় থাকে, তাই প্রথমে নামে আর পরে দামে সাজালে একই দামের পণ্য নামের ক্রমে থাকে।

ঝালিয়ে নিন: পর্ব ১৬, পর্ব ১৫

খ-০৫একটি nested array-কে চাইলে নির্দিষ্ট গভীরতা পর্যন্ত সমতল করার flatten আর একটি groupBy function লিখুন। (মাঝারি)

পদ্ধতি: flatten — প্রতিটি উপাদান দেখি; array হলে আর গভীরতা বাকি থাকলে নিজেকে depth - 1 দিয়ে ডাকি, না হলে সরাসরি যোগ করি। groupBy — প্রতিটি উপাদানের key বের করি, সেই key-এর তালিকায় যোগ করি। ভাষার নিজস্ব (built-in) সমতুল্য দুটির কথাও লিখুন: Array.prototype.flat (ES2019) আর Object.groupBy (ES2024).

function flatten(arr, depth = Infinity) {
  const out = [];
  for (const item of arr) {
    if (Array.isArray(item) && depth > 0) out.push(...flatten(item, depth - 1));
    else out.push(item);
  }
  return out;
}
console.log(flatten([1, [2, [3, [4]]], 5]));
console.log(flatten([1, [2, [3, [4]]]], 1));
console.log([1, [2, [3, [4]]]].flat(Infinity));

function groupBy(list, keyFn) {
  const groups = Object.create(null);     // prototype নেই: '__proto__' key-ও নিরাপদ
  for (const item of list) {
    const k = keyFn(item);
    (groups[k] ??= []).push(item);
  }
  return groups;
}
const sales = [{ cat: 'খাবার', tk: 120 }, { cat: 'যাতায়াত', tk: 60 }, { cat: 'খাবার', tk: 80 }];
const g = groupBy(sales, s => s.cat);
console.log(Object.keys(g), g['খাবার'].map(s => s.tk));

আউটপুট: [ 1, 2, 3, 4, 5 ]; গভীরতা ১-এ শুধু এক স্তর খোলে — [ 1, 2, [ 3, [ 4 ] ] ]; built-in flat(Infinity) দেয় [ 1, 2, 3, 4 ]; শেষ লাইনে [ 'খাবার', 'যাতায়াত' ] [ 120, 80 ]. খাতায় যোগ করুন: flatten-এর সময় O(n), কিন্তু খুব গভীর nesting-এ recursion stack overflow ঘটাতে পারে, আর বিশাল array-তে push(...x) আর্গুমেন্টের সীমায় পৌঁছাতে পারে — তখন লুপে একটি একটি করে push. groupBy-তে Object.create(null) দেওয়া হয়েছে যাতে '__proto__' বা 'constructor' নামের key prototype-এর সাথে না জড়ায়; ??= (ES2021) প্রথমবার খালি তালিকা বানায়। Object.groupBy নিজেও null-prototype object ফেরত দেয়, তবে Node 21-এর আগে নেই — Node 20-এ নিজের groupBy লাগবে।

ঝালিয়ে নিন: পর্ব ১৫, পর্ব ১৬

খ-০৬Map আর সাধারণ object-এর পার্থক্য লিখুন। Set আর WeakMap কোথায় কাজে লাগে? (মাঝারি)
বিষয়objectMap
key-এর টাইপশুধু string আর symbol (সংখ্যা string হয়ে যায়)যেকোনো মান — object, function-ও
আকারObject.keys(o).lengthmap.size
ক্রমনিয়ম জটিল (পূর্ণসংখ্যার মতো key আগে)সবসময় ঢোকানোর ক্রম
উত্তরাধিকারসূত্রে keyprototype থেকে আসতে পারেনেই
ঘন ঘন যোগ-মোছাতুলনামূলক ধীর হতে পারেএ কাজের জন্যই বানানো
JSONসরাসরিসরাসরি নয় — Object.fromEntries লাগে

Set: অনন্য মানের সংগ্রহ — [...new Set(arr)] দিয়ে duplicate সরানো, “দেখা হয়েছে কি না” গড়ে O(1)-এ। WeakMap: key শুধু object, আর key-কে GC থেকে আটকায় না — DOM node বা object-এর সাথে বাড়তি ডেটা (cache, private ডেটা) জুড়তে, যাতে object মুছে গেলে ডেটাও মুছে যায়, memory leak ছাড়া। সীমা: WeakMap-এ লুপ চালানো বা size জানা যায় না।

ঝালিয়ে নিন: পর্ব ১৮ · Map, Set, WeakMap

খ-০৭JSON.stringify কোন কোন মান হারায় বা বদলে দেয়? (মাঝারি)

object-এর property-তে undefined, function আর symbol মান থাকলে সেই property বাদ যায় (array-র ভেতরে এরা null হয়); NaN আর Infinity হয় null; Date হয় ISO string (toJSON ডাকার কারণে) — parse করলে আর Date থাকে না; Map ও Set হয় {}; BigInt-এ TypeError; circular reference-এ TypeError: Converting circular structure to JSON. উদাহরণ: JSON.stringify({a: undefined, c: NaN, d: new Date(0)}) → {"c":null,"d":"1970-01-01T00:00:00.000Z"}. সমাধানের পথ: replacer/reviver function, নিজের toJSON, আর নেটওয়ার্ক থেকে আসা JSON সবসময় schema দিয়ে যাচাই।

ঝালিয়ে নিন: পর্ব ১৯ · JSON

খ-০৮destructuring, spread আর rest কী? একই ... দুই কাজ করে কীভাবে? (সহজ)

Destructuring (ES2015) object বা array থেকে মান খুলে variable-এ রাখে: const { name, price = 0 } = product;, const [first, second] = list;. ... অবস্থানভেদে দুই কাজ করে: মান যেখানে দরকার সেখানে spread (ছড়ানো) — [...a, ...b], {...defaults, ...options}, Math.max(...nums); আর যেখানে মান গ্রহণ করা হয় সেখানে rest (জড়ো করা) — function sum(...nums), const { password, ...safeUser } = user;. শেষ উদাহরণটি API-র উত্তর থেকে গোপন field বাদ দেওয়ার পরিচিত কৌশল। সতর্কতা: spread shallow copy করে।

ঝালিয়ে নিন: পর্ব ১৭

খ-০৯JavaScript-এর Date নিয়ে তিনটি প্রচলিত ফাঁদ লিখুন। তারিখ বাংলায় দেখাবেন কীভাবে? (সহজ)

ফাঁদ ১ — মাস ০ থেকে: new Date(2026, 0, 31) হলো ৩১ জানুয়ারি; ডিসেম্বর হলো 11. ফাঁদ ২ — overflow চুপচাপ: new Date(2026, 1, 30) error দেয় না, গড়িয়ে ২ মার্চ হয়ে যায়। ফাঁদ ৩ — time zone: Date আসলে একটি UTC মুহূর্ত (epoch থেকে মিলিসেকেন্ড); getHours দেখায় যন্ত্রের লোকাল সময়ে, toISOString দেখায় UTC-তে — সার্ভার আর ব্রাউজারের time zone আলাদা হলে তারিখ একদিন সরে যেতে পারে।

বাংলায় দেখাতে: new Intl.DateTimeFormat('bn-BD', { dateStyle: 'long', timeZone: 'Asia/Dhaka' }).format(d). সংরক্ষণে UTC (ISO 8601 string বা timestamp), দেখানোয় লোকাল — এটাই নিয়ম।

ঝালিয়ে নিন: পর্ব ২০ · তারিখ, সময় আর Intl

৫ · অংশ গ — function ও object গভীরে (মডিউল ৪)

রিভিশনের জন্য: পর্ব ২২, পর্ব ২৩, পর্ব ২৪, পর্ব ২৫, পর্ব ২৬, পর্ব ২৭, পর্ব ২৮, পর্ব ২৯, পর্ব ৩০.

এই মডিউল থেকে লিখিত আর ভাইভা — দুই জায়গাতেই সবচেয়ে বেশি “ব্যাখ্যা করুন” প্রশ্ন আসে। closure-এর পাঁচ অংশের সম্পূর্ণ উত্তর আপনি অংশ ২-এর ডায়াগ্রামে দেখেছেন; এখানে তার চালানো যায় এমন প্রমাণ আর বাকি প্রশ্নগুলো।

গ-০১closure কী? উদাহরণসহ লিখুন। লুপে var আর let দিয়ে setTimeout কেন আলাদা ফল দেয়? (মাঝারি)

সংজ্ঞা: closure হলো একটি function আর তার জন্মস্থানের variable-গুলোর (lexical scope) সংযোগ — বাইরের function শেষ হলেও ভেতরের function সেগুলো পড়তে ও বদলাতে পারে। closure মান নয়, variable ধরে রাখে।

function makeCounter() {
  let count = 0;                         // বাইরে থেকে সরাসরি ছোঁয়া যায় না
  return { inc: () => ++count, get: () => count };
}
const a = makeCounter();
const b = makeCounter();
a.inc(); a.inc(); b.inc();
console.log('a:', a.get(), 'b:', b.get());

for (var i = 0; i < 3; i++) setTimeout(() => console.log('var:', i));
for (let j = 0; j < 3; j++) setTimeout(() => console.log('let:', j));

প্রথম লাইন a: 2 b: 1 — প্রতিটি makeCounter() ডাক নতুন একটি count বানায়, তাই দুটি counter একে অপরকে ছোঁয় না। এরপর var: 3 তিনবার, তারপর let: 0, let: 1, let: 2. কারণ: var-এর পুরো function-এ (এখানে global-এ) একটিই i; timer চলার সময় লুপ শেষ, i তখন 3, আর তিনটি callback একই variable দেখে। let-এর জন্য মানদণ্ড প্রতি পুনরাবৃত্তিতে নতুন binding বানায়, তাই প্রতিটি callback নিজের j ধরে রাখে। ES2015-এর আগে এর সমাধান ছিল IIFE দিয়ে প্রতিবার নতুন scope বানানো।

সুবিধা ও সীমা: private state, function factory, memoization, debounce — সবই closure. কিন্তু closure যা ধরে রাখে তা GC হয় না; বড় DOM বা ডেটা ধরে রাখা event listener না সরালে memory leak হয়।

ঝালিয়ে নিন: পর্ব ২২ · scope chain আর closure, পর্ব ০৭

গ-০২currying কী? একটি সাধারণ curry আর একটি memoize function লিখুন। (কঠিন)

সংজ্ঞা: currying হলো অনেক আর্গুমেন্টের একটি function-কে এমন রূপ দেওয়া, যাতে আর্গুমেন্টগুলো এক এক করে (বা ভাগে ভাগে) দেওয়া যায়: f(a, b, c) → f(a)(b)(c). memoization হলো একই ইনপুটের ফল cache-এ রেখে পরেরবার আবার হিসাব না করা — শুধু pure function-এর জন্য নিরাপদ। পদ্ধতি: curry জমানো আর্গুমেন্ট গোনে; fn.length-এর সমান হলে আসল function ডাকে, নইলে আরও আর্গুমেন্টের জন্য নতুন function ফেরত দেয় (closure-এ আগেরগুলো জমা থাকে)। memoize একটি Map-কে closure-এ রাখে।

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) return fn.apply(this, args);
    return (...more) => curried.apply(this, [...args, ...more]);
  };
}
const bill = (rate, qty, discount) => rate * qty - discount;
const cb = curry(bill);
console.log(cb(50)(3)(20), cb(50, 3)(20), cb(50)(3, 20));
const teaBill = cb(15);                  // দাম আটকে রাখা হলো
console.log(teaBill(4)(0));

function memoize(fn, keyFn = (...a) => JSON.stringify(a)) {
  const cache = new Map();
  return function (...args) {
    const key = keyFn(...args);
    if (cache.has(key)) return cache.get(key);
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}
let calls = 0;
const slowSquare = n => { calls++; return n * n; };
const fastSquare = memoize(slowSquare);
console.log(fastSquare(9), fastSquare(9), fastSquare(4), 'calls:', calls);

আউটপুট: 130 130 130 — তিনভাবে ভাগ করে দিলেও ফল এক (50 × 3 − 20); 60 — teaBill হলো partial application, দাম 15 আগে থেকেই বসানো; 81 81 16 calls: 2 — দ্বিতীয় fastSquare(9) cache থেকে এসেছে, তাই আসল function মাত্র দুবার চলেছে। খাতায় সীমাগুলো লিখুন: fn.length default বা rest parameter গোনে না, তাই (a, b = 1) => …-এর জন্য এই curry কাজ করবে না; JSON.stringify key object-এর পরিচয় বা function আলাদা করতে পারে না; আর cache সীমাহীন বাড়ে — বাস্তবে আকার সীমিত LRU cache বা WeakMap লাগে। apply(this, …) রাখায় method হিসেবেও this হারায় না।

ঝালিয়ে নিন: পর্ব ২৩ · currying আর composition, পর্ব ২২ · memoization

গ-০৩this-এর মান কে ঠিক করে? চারটি নিয়ম আর arrow function-এর ব্যতিক্রম লিখুন। (মাঝারি)

this-এর মান ঠিক হয় function কীভাবে ডাকা হলো তা দিয়ে, কোথায় লেখা হলো তা দিয়ে নয় (arrow বাদে)। অগ্রাধিকার অনুযায়ী:

  1. new binding: new Shop() — নতুন তৈরি object.
  2. explicit: f.call(obj), f.apply(obj), f.bind(obj) — obj.
  3. implicit: cart.total() — ডটের বাঁ দিকের object, cart.
  4. default: সাধারণ f() — strict mode-এ (module ও class-এর ভেতরে সবসময় strict) undefined; sloppy mode-এ global object (ব্রাউজারে window).

Arrow: নিজের this নেই; যেখানে লেখা হয়েছে সেখানকার বাইরের this নেয় (lexical this), আর call/bind দিয়েও বদলানো যায় না। ক্লাসিক ফাঁদ: const f = cart.total; f(); — method আলাদা করে ডাকলে implicit binding হারায় (lost this); একইভাবে setTimeout(cart.total, 0). সমাধান: cart.total.bind(cart) বা () => cart.total().

ঝালিয়ে নিন: পর্ব ২৪ · this, call, apply আর bind

গ-০৪call, apply আর bind-এর পার্থক্য লিখুন। (সহজ)
methodকখন চলেআর্গুমেন্টফেরত
f.call(obj, a, b)সাথে সাথেআলাদা আলাদাf-এর ফল
f.apply(obj, [a, b])সাথে সাথেএকটি array (বা array-like)f-এর ফল
f.bind(obj, a)এখন নয় — পরেআগে থেকে কিছু বসানো যায় (partial)this স্থায়ীভাবে বাঁধা নতুন function

মনে রাখার সহজ সূত্র: Apply = Array. bind একবার বাঁধলে আবার bind বা call দিয়ে this বদলায় না (তবে new দিয়ে ডাকলে নতুন object পায়)। আজকাল spread থাকায় apply কম লাগে: Math.max(...nums).

ঝালিয়ে নিন: পর্ব ২৪

গ-০৫prototype chain চিত্রসহ ব্যাখ্যা করুন। obj.toString() কোথা থেকে আসে? (মাঝারি)

সংজ্ঞা: প্রতিটি object-এর একটি লুকানো সংযোগ থাকে আরেকটি object-এর দিকে — তার prototype ([[Prototype]], পড়া যায় Object.getPrototypeOf দিয়ে)। কোনো property পড়লে engine প্রথমে object-এর নিজের property খোঁজে; না পেলে prototype-এ, তারপর তার prototype-এ … যতক্ষণ না null-এ পৌঁছায়। এই শিকলই prototype chain.

class Product { constructor(n) { this.name = n; } label() { return '#' + this.name; } }
const tea = new Product('চা');

 tea  { name: 'চা' }                         ← নিজের property
  │ [[Prototype]]
  ▼
 Product.prototype { label(), constructor }  ← class-এর method এখানে
  │ [[Prototype]]
  ▼
 Object.prototype { toString(), hasOwnProperty(), … }
  │ [[Prototype]]
  ▼
 null                                        ← খোঁজা শেষ: undefined

tea.label()     → Product.prototype-এ পাওয়া গেল
tea.toString()  → Object.prototype-এ পাওয়া গেল → '[object Object]'
tea.price       → কোথাও নেই → undefined

আরও লিখুন: property লিখলে শিকল ধরে ওঠে না — নিজের property তৈরি হয় (shadowing). method prototype-এ থাকায় হাজারটি object একটিই function ভাগ করে — মেমরি বাঁচে। instanceof শিকলে Product.prototype আছে কি না দেখে। Object.create(null) শিকলহীন object বানায়। সীমা: লম্বা শিকল খোঁজা ধীর করে, আর Object.prototype-এ কিছু যোগ করা (বা prototype pollution আক্রমণ) সব object-কে প্রভাবিত করে।

ঝালিয়ে নিন: পর্ব ২৫ · prototype chain

গ-০৬JavaScript-এর class কি শুধু syntactic sugar? constructor function-এর সাথে পার্থক্য আর private field লিখুন। (মাঝারি)

মূলত হ্যাঁ — class (ES2015) ভেতরে সেই prototype ব্যবস্থাই ব্যবহার করে; typeof Product হলো 'function'. কিন্তু শুধু চেহারার পার্থক্য নয়: class new ছাড়া ডাকলে TypeError: Class constructor Product cannot be invoked without 'new'; class-এর ভেতর সবসময় strict mode; method-গুলো non-enumerable; class ঘোষণা TDZ মানে (ঘোষণার আগে ব্যবহার করা যায় না); আর extends/super দিয়ে built-in (যেমন Error, Array) থেকে ঠিকভাবে উত্তরাধিকার নেওয়া যায়।

Private field (ES2022): #balance — class-এর বাইরে থেকে পড়ার চেষ্টা SyntaxError (কোড চালানোর আগেই), রানটাইমে ফাঁকি দেওয়ার উপায় নেই। আগের প্রথা _balance ছিল শুধু একটি সম্মতি, আর closure বা WeakMap দিয়ে আসল গোপনীয়তা বানাতে হতো। static member আর static {} block-ও আছে। সীমা: subclass-ও parent-এর #field দেখতে পায় না।

ঝালিয়ে নিন: পর্ব ২৬ · class আর private field

গ-০৭iterator protocol কী? generator কীভাবে তা সহজ করে? (মাঝারি)

একটি object iterable হয়, যদি তার [Symbol.iterator]() method থাকে, যা একটি iterator ফেরত দেয়; iterator হলো এমন object যার next() প্রতিবার { value, done } দেয়। for…of, spread, destructuring, Array.from — সবাই এই চুক্তি মানে।

Generator (function*) এই চুক্তি নিজে বানিয়ে দেয়: প্রতিটি yield-এ function থেমে একটি মান দেয়, পরের next()-এ ঠিক সেখান থেকে চলে। উদাহরণ: function* ids() { let n = 1; while (true) yield n++; } — অসীম ক্রম, কিন্তু মান তৈরি হয় চাওয়ামাত্র (lazy), তাই মেমরি লাগে না। ব্যবহার: পাতায় পাতায় ডেটা আনা, বড় ফাইল লাইন ধরে পড়া, async generator ও for await…of.

ঝালিয়ে নিন: পর্ব ২৭

গ-০৮Proxy কী? বাস্তবে কোথায় ব্যবহার হয়? (কঠিন)

Proxy (ES2015) একটি object-এর চারপাশে মোড়ক, যা property পড়া, লেখা, মোছা, in পরীক্ষা ইত্যাদি মৌলিক কাজ মাঝপথে ধরে নিজের নিয়ম চালাতে দেয়: new Proxy(target, { get(t, key, r) {…}, set(t, key, v, r) {…} }). handler-এর এই method-গুলোকে trap বলে, আর trap-এর ভেতরে আসল কাজটি করতে Reflect-এর একই নামের method (Reflect.get, Reflect.set) ব্যবহার করা হয়।

ব্যবহার: validation (ঋণাত্মক দাম লিখতে না দেওয়া), লগিং, ডিফল্ট মান, আর framework-এর reactivity — Vue 3 পরিবর্তন টের পেতে Proxy ব্যবহার করে। সীমা: প্রতিটি কাজে বাড়তি function call, তাই hot path-এ ধীর; #private field আছে এমন class instance বা Map-এর মতো built-in মোড়ালে method ভেঙে যেতে পারে; আর proxy !== target, তাই পরিচয় তুলনায় বিভ্রান্তি।

ঝালিয়ে নিন: পর্ব ২৮ · Symbol, Proxy আর Reflect

গ-০৯try/catch/finally কীভাবে কাজ করে? একটি custom error class লিখুন আর cause-এর ব্যবহার দেখান। (মাঝারি)

try-এ error ছুড়লে বাকি অংশ বাদ দিয়ে catch-এ যায়; finally সবসময় চলে — try-এ return থাকলেও (আর finally-তে return দিলে তা আগের return বা error-কে চাপা দেয় — তাই সেখানে return দেবেন না)। try/catch শুধু synchronous error বা await করা Promise ধরে; setTimeout-এর callback-এর ভেতরের error বাইরের try ধরতে পারে না।

class PaymentError extends Error {
  constructor(message, options) {
    super(message, options);           // options-এ { cause } যায় (ES2022)
    this.name = 'PaymentError';
  }
}
try {
  try { JSON.parse('{bad'); }
  catch (err) { throw new PaymentError('পেমেন্টের উত্তর পড়া গেল না', { cause: err }); }
} catch (e) {
  console.log(e.name, e instanceof PaymentError, e.cause.name);
}
// আউটপুট: PaymentError true SyntaxError

কেন cause: নিচের স্তরের আসল কারণ না হারিয়ে উপরের স্তরে অর্থবহ বার্তা দেওয়া যায় — log-এ দুটোই থাকে। নিয়ম: শুধু Error (বা তার subclass) ছুড়ুন, string নয় — নইলে stack trace থাকে না; error গিলে ফেলবেন না (খালি catch); যে error সামলাতে পারেন না, তা আবার ছুড়ুন।

ঝালিয়ে নিন: পর্ব ২৯ · custom error আর cause

গ-১০regex-এ greedy আর lazy quantifier-এর পার্থক্য কী? ReDoS কী? (কঠিন)

greedy quantifier (*, +, {n,}) যতটা পারে তত বেশি মেলায়, তারপর দরকার হলে পিছিয়ে আসে; lazy (*?, +?) যতটা পারে তত কম। উদাহরণ: '<b>চা</b><b>পান</b>'-এ /<b>.*<\/b>/ পুরো string মেলায়, /<b>.*?<\/b>/ শুধু প্রথম <b>চা</b>.

ReDoS: JavaScript-এর regex engine backtracking করে। /^(a+)+$/-এর মতো nested quantifier-এ মেলে না এমন ইনপুট ('aaaa…a!') দিলে চেষ্টার সংখ্যা ইনপুটের দৈর্ঘ্যের সাথে সূচকীয় হারে বাড়ে (catastrophic backtracking) — একটি অনুরোধেই সার্ভারের একমাত্র thread আটকে যেতে পারে। প্রতিরোধ: nested quantifier এড়ানো, ইনপুটের দৈর্ঘ্য সীমিত করা, আর সম্ভব হলে regex-এর বদলে সাধারণ parsing.

ঝালিয়ে নিন: পর্ব ৩০ · regular expression

৬ · অংশ ঘ — Asynchronous JavaScript (মডিউল ৫)

রিভিশনের জন্য: পর্ব ৩১, পর্ব ৩২, পর্ব ৩৩, পর্ব ৩৪, পর্ব ৩৫, পর্ব ৩৬.

ঘ-০১event loop চিত্রসহ ব্যাখ্যা করুন। task আর microtask-এর পার্থক্য কী? (কঠিন)

সংজ্ঞা: JavaScript একটি thread-এ চলে — একটিই call stack. event loop হলো সেই ব্যবস্থা, যা stack খালি হলে অপেক্ষমাণ কাজের সারি থেকে পরের কাজ এনে চালায়। timer, নেটওয়ার্ক, click — এসবের অপেক্ষা করে ব্রাউজার (Web API) বা Node (libuv), JavaScript নিজে নয়।

 ┌──────────────┐   setTimeout, fetch,   ┌──────────────────────┐
 │  Call stack  │ ──── addEventListener ─►│ Web API / libuv      │
 │ (একটিই)      │                         │ (timer, network, I/O)│
 └──────▲───────┘                         └──────────┬───────────┘
        │ stack খালি হলে                             │ কাজ শেষ হলে callback
        │                                            ▼
 ┌──────┴───────────────┐  আগে সব ──►  ┌───────────────────────────┐
 │ Microtask queue      │              │ Task queue                │
 │ Promise.then, await, │  তারপর একটি ►│ setTimeout, click, message│
 │ queueMicrotask       │              └───────────────────────────┘
 └──────────────────────┘
 প্রতি ঘূর্ণন: একটি task → microtask queue পুরো খালি → (দরকার হলে) render
console.log('1: sync শুরু');
setTimeout(() => console.log('8: setTimeout — task'), 0);
Promise.resolve()
  .then(() => console.log('4: then ১ — microtask'))
  .then(() => console.log('7: then ২ — microtask'));
queueMicrotask(() => console.log('5: queueMicrotask'));
(async () => {
  console.log('2: async function-এর শুরু — এখনো sync');
  await null;
  console.log('6: await-এর পরের অংশ — microtask');
})();
console.log('3: sync শেষ, stack খালি হলো');

আউটপুট ১ থেকে ৮ ক্রমে — কোডের লেখার ক্রমে নয়। async function-এর প্রথম await পর্যন্ত অংশ (২) synchronous. stack খালি হলে (৩-এর পরে) microtask queue খালি করা হয় ঢোকার ক্রমে: then ১ (৪), queueMicrotask (৫), await-এর পরের অংশ (৬); then ১ শেষ হওয়ার পরেই then ২ queue-তে ঢোকে, তাই সে আসে ৭-এ। সব microtask শেষ হলে তবেই task — setTimeout(…, 0) (৮)। খাতায় লিখুন: “0 ms” মানে “অন্তত 0 ms পরে, পরের task হিসেবে” — সাথে সাথে নয়। আর microtask অবিরাম নতুন microtask যোগ করলে task ও render কখনো আসে না — পাতা জমে যায় (microtask starvation).

ঝালিয়ে নিন: পর্ব ৩১ · event loop, পর্ব ০৫ · call stack

ঘ-০২callback hell কী? এর সমাধান কীভাবে বিবর্তিত হয়েছে? (সহজ)

একটি async কাজের পর আরেকটি, তারপর আরেকটি — প্রতিটি আগেরটির callback-এর ভেতরে লিখলে কোড ডানে সরতে থাকে (“pyramid of doom”), প্রতিটি স্তরে আলাদা error পরীক্ষা লাগে, আর কে কখন callback ডাকবে তার নিয়ন্ত্রণ অন্যের হাতে চলে যায় (inversion of control) — একে বলে callback hell. বিবর্তন: named function-এ ভাগ করা → Promise (ES2015) দিয়ে .then chain, একটি .catch-এ সব error → async/await (ES2017) দিয়ে প্রায় synchronous চেহারার কোড, সাধারণ try/catch. Node-এর error-first callback API-কে util.promisify বা fs/promises দিয়ে Promise-এ আনা যায়।

ঝালিয়ে নিন: পর্ব ৩২ · callback hell

ঘ-০৩Promise-এর অবস্থাগুলো লিখুন। Promise.all, allSettled, race আর any-এর পার্থক্য টেবিলে দেখান। (মাঝারি)

একটি Promise প্রথমে pending; তারপর একবারই fulfilled (মান নিয়ে) বা rejected (কারণ নিয়ে) হয় — দুটিকে একসাথে বলে settled. একবার settled হলে আর বদলায় না।

combinatorকখন fulfilledকখন rejectedকোথায় ব্যবহার
Promise.all (ES2015)সব fulfilled হলে — মানের array, ইনপুটের ক্রমেপ্রথম rejection-এইসবগুলো লাগবেই: পণ্য + দাম + স্টক
Promise.allSettled (ES2020)সব settled হলে — {status, value} বা {status, reason}কখনো নাড্যাশবোর্ডের আলাদা উইজেট, যেকোনোটি ব্যর্থ হতে পারে
Promise.race (ES2015)প্রথম settled-টি fulfilled হলেপ্রথম settled-টি rejected হলেtimeout: কাজ বনাম টাইমার
Promise.any (ES2021)প্রথম fulfilled-টিতেসবগুলো rejected হলে — AggregateErrorএকাধিক mirror সার্ভার, যেটি আগে সাড়া দেয়

সতর্কতা: Promise.all reject হলেও বাকি কাজগুলো থামে না — শুধু তাদের ফল উপেক্ষিত হয়; থামাতে AbortController লাগে। খালি array পেলে all ও allSettled সাথে সাথে [] দেয়, any সাথে সাথে AggregateError-এ reject হয়, আর race চিরকাল pending থাকে।

ঝালিয়ে নিন: পর্ব ৩৩ · Promise আর combinator

ঘ-০৪Promise.all-এর একটি polyfill লিখুন। (কঠিন)

চুক্তি: iterable নেয়; সব fulfilled হলে মানের array — ইনপুটের ক্রমে, শেষ হওয়ার ক্রমে নয়; প্রথম rejection-এ reject; সাধারণ মান (Promise নয়) এলে তাকে fulfilled ধরা; খালি ইনপুটে সাথে সাথে []. পদ্ধতি: একটি নতুন Promise ফেরত দিই; প্রতিটি উপাদানকে Promise.resolve দিয়ে মুড়ে then লাগাই; ফল রাখি তার সূচকে; একটি counter দিয়ে গুনি কয়টি বাকি।

function promiseAll(iterable) {
  return new Promise((resolve, reject) => {
    const items = Array.from(iterable);
    const results = new Array(items.length);
    let left = items.length;
    if (left === 0) return resolve(results);       // খালি ইনপুট: সাথে সাথে []
    items.forEach((item, i) => {
      Promise.resolve(item).then(value => {        // সাধারণ মানও চলবে
        results[i] = value;                        // ক্রম ঠিক রাখে সূচক, সময় নয়
        if (--left === 0) resolve(results);
      }, reject);                                  // প্রথম ব্যর্থতাতেই reject
    });
  });
}
const wait = (ms, v, fail) =>
  new Promise((res, rej) => setTimeout(() => (fail ? rej(new Error(v)) : res(v)), ms));

promiseAll([wait(60, 'ক'), 42, wait(10, 'খ')]).then(r => console.log('all:', r));
promiseAll([wait(40, 'ok'), wait(5, 'নেটওয়ার্ক বিকল', true)])
  .catch(e => console.log('rejected:', e.message));
promiseAll([]).then(r => console.log('empty:', r));
Promise.allSettled([wait(20, 'x'), wait(25, 'y', true)])
  .then(r => console.log('allSettled:', r.map(s => s.status)));

আউটপুটের ক্রম সময় অনুযায়ী: empty: [] (সাথে সাথে, microtask-এ), rejected: নেটওয়ার্ক বিকল (৫ ms-এ — ৪০ ms-এর কাজটির জন্য অপেক্ষা করেনি), allSettled: [ 'fulfilled', 'rejected' ] (২৫ ms-এ — rejection থাকা সত্ত্বেও fulfilled হয়েছে), আর শেষে all: [ 'ক', 42, 'খ' ] (৬০ ms-এ)। লক্ষ করুন, 'খ' আগে শেষ হলেও array-তে তৃতীয় স্থানে — কারণ আমরা push নয়, results[i] ব্যবহার করেছি; এটিই পরীক্ষকের প্রিয় ফাঁদ। প্রথম reject-এর পরে আরও resolve/reject ডাক এলেও কিছু হয় না, কারণ Promise একবারই settled হয়।

ঝালিয়ে নিন: পর্ব ৩৩

ঘ-০৫async/await কী? error কীভাবে সামলাবেন? sequential আর parallel await-এর পার্থক্য লিখুন। (মাঝারি)

async function (ES2017) সবসময় একটি Promise ফেরত দেয়; ভেতরে await একটি Promise settled হওয়া পর্যন্ত শুধু ওই function-কে থামায় — thread নয়, বাকি পাতা চলতে থাকে। rejected হলে await সেই কারণ ছুড়ে দেয়, তাই সাধারণ try/catch কাজ করে।

// sequential: মোট সময় ≈ a + b — শুধু তখনই, যখন b-এর জন্য a-এর ফল লাগে
const user = await getUser(id);
const orders = await getOrders(user.id);

// parallel: মোট সময় ≈ max(a, b) — একে অপরের ওপর নির্ভর না করলে
const [products, offers] = await Promise.all([getProducts(), getOffers()]);

ফাঁদ: forEach-এর ভেতরে await অপেক্ষা করে না — for…of (একটি একটি করে) বা Promise.all + map (একসাথে) ব্যবহার করুন। catch ছাড়া rejected Promise হলো unhandled rejection; Node 15 থেকে ডিফল্টে এতে process বন্ধ হয়ে যায়। Module-এ top-level await চলে (ES2022).

ঝালিয়ে নিন: পর্ব ৩৪ · async/await

ঘ-০৬fetch 404 বা 500 পেলে কি reject করে? সঠিকভাবে একটি JSON API ডাকার কোড লিখুন। (মাঝারি)

না। fetch reject করে শুধু নেটওয়ার্ক ব্যর্থ হলে (সংযোগ নেই, DNS ব্যর্থ, CORS আটকালে) বা abort হলে। সার্ভার যেকোনো উত্তর দিলেই — 404, 500-সহ — Promise fulfilled হয়; তখন res.ok (status 200–299) নিজে পরীক্ষা করতে হয়।

async function getJSON(url, { signal } = {}) {
  const res = await fetch(url, { signal, headers: { Accept: 'application/json' } });
  if (!res.ok) throw new Error(`HTTP ${res.status} — ${url}`);
  return res.json();                 // এটিও Promise; ভুল JSON-এ SyntaxError
}

আরও লিখুন: body একবারই পড়া যায় (res.json() দুবার ডাকলে TypeError); POST-এ JSON.stringify আর Content-Type: application/json header লাগে; fetch নিজে কোনো timeout দেয় না — AbortSignal.timeout(5000) দিন।

ঝালিয়ে নিন: পর্ব ৩৫ · fetch আর HTTP

ঘ-০৭debounce আর throttle-এর পার্থক্য লিখুন। একটি debounce function লিখে দেখান। (মাঝারি)

debounce: ঘটনা থামার পর নির্দিষ্ট সময় চুপ থাকলে তবেই একবার চালায় — শেষ ঘটনাটি গোনে। উদাহরণ: search box-এ টাইপ থামার পরে API call. throttle: ঘটনা যত ঘন ঘনই আসুক, নির্দিষ্ট সময়ে সর্বোচ্চ একবার চালায় — নিয়মিত বিরতিতে। উদাহরণ: scroll-এর সময় অবস্থান হালনাগাদ। লিফটের উপমা: debounce হলো দরজা — কেউ ঢুকলে আবার অপেক্ষা শুরু; throttle হলো মেট্রোর সময়সূচি — যত যাত্রীই আসুক, নির্দিষ্ট বিরতিতে একটি ট্রেন।

function debounce(fn, wait) {
  let timer;
  return function (...args) {
    clearTimeout(timer);                              // আগের অপেক্ষা বাতিল
    timer = setTimeout(() => fn.apply(this, args), wait);
  };
}
const search = debounce(q => console.log('API call:', q), 150);

// ব্যবহারকারী দ্রুত টাইপ করছেন: প্রতি ৩০ ms-এ একটি করে অক্ষর
['d', 'dh', 'dha', 'dhak', 'dhaka'].forEach((q, i) => setTimeout(() => search(q), i * 30));
// একটু থেমে আবার টাইপ
setTimeout(() => search('sylhet'), 600);

ছয়টি ডাকের জায়গায় API call মাত্র দুটি: API call: dhaka (শেষ অক্ষরের ১৫০ ms পরে) আর API call: sylhet. মাঝের ডাকগুলোর timer প্রতিবার clearTimeout-এ বাতিল হয়েছে। timer variable closure-এ বাঁচে, তাই প্রতিটি debounced function-এর নিজের timer. fn.apply(this, args) রাখায় শেষ ডাকের আর্গুমেন্ট আর this দুটোই ঠিক থাকে। উন্নত রূপে যোগ করা হয় cancel() আর leading edge (প্রথম ঘটনাতেই একবার চালানো)। বাস্তবে debounce-এর সাথে পুরোনো অনুরোধ AbortController দিয়ে বাতিলও করুন, নইলে ধীর পুরোনো উত্তর নতুনটির পরে এসে ফল উল্টে দিতে পারে।

ঝালিয়ে নিন: পর্ব ৩৬ · debounce আর throttle

ঘ-০৮AbortController কী? একটি নিরাপদ retry নীতি কেমন হওয়া উচিত? (কঠিন)

AbortController একটি async কাজ বাতিলের সংকেত দেয়: const ac = new AbortController(); fetch(url, { signal: ac.signal }); ac.abort(); — fetch তখন AbortError নামের DOMException দিয়ে reject করে। ব্যবহার: পাতা বদলালে পুরোনো অনুরোধ বাতিল, timeout (AbortSignal.timeout(ms)), নতুন search এলে পুরোনোটি বাতিল। একই signal দিয়ে event listener-ও একসাথে সরানো যায়।

retry নীতি: (১) শুধু সাময়িক ব্যর্থতায় — নেটওয়ার্ক ভাঙা, 503, 429; 400 বা 404-এ নয়। (২) শুধু idempotent অনুরোধে (GET, PUT, DELETE), অথবা POST-এ idempotency key থাকলে — নইলে দুবার অর্ডার বা দুবার টাকা কাটা। (৩) exponential backoff — অপেক্ষা ২০০, ৪০০, ৮০০ ms… — সাথে এলোমেলো jitter, যাতে হাজার client একসাথে আবার আঘাত না করে। (৪) সর্বোচ্চ চেষ্টার সীমা, আর Retry-After header মানা। (৫) ব্যবহারকারী বাতিল করলে retry-ও থামানো (signal পরীক্ষা)।

ঝালিয়ে নিন: পর্ব ৩৬ · AbortController আর retry

৭ · অংশ ঙ — ব্রাউজার ও DOM (মডিউল ৬)

রিভিশনের জন্য: পর্ব ৩৭, পর্ব ৩৮, পর্ব ৩৯, পর্ব ৪০, পর্ব ৪১, পর্ব ৪২, পর্ব ৪৩, পর্ব ৪৪.

ঙ-০১DOM কী? innerHTML, textContent আর innerText-এর পার্থক্য লিখুন। (সহজ)

সংজ্ঞা: DOM (Document Object Model) হলো ব্রাউজারের বানানো HTML পাতার জীবন্ত গাছ-আকৃতির object মডেল — প্রতিটি element, লেখা আর attribute একটি node. JavaScript এই গাছ পড়ে আর বদলায়, আর ব্রাউজার বদল দেখে পাতা নতুন করে আঁকে। DOM JavaScript-এর অংশ নয়; এটি ব্রাউজারের Web API (Node.js-এ নেই)।

propertyকী পড়ে বা লেখেনিরাপত্তা ও খরচ
innerHTMLHTML হিসেবে — লেখা string parse হয়ে নতুন element হয়ব্যবহারকারীর ইনপুট দিলে XSS-এর ঝুঁকি
textContentশুধু লেখা, সব node-এর (লুকানো অংশসহ)নিরাপদ — HTML হিসেবে পড়া হয় না; দ্রুত
innerTextপাতায় যেমন দেখা যায় তেমন লেখা (CSS মেনে)নিরাপদ, কিন্তু পড়তে layout হিসাব লাগে — ধীর

উপসংহার: ব্যবহারকারীর দেওয়া লেখা দেখাতে textContent; কাঠামো বানাতে createElement বা <template>; HTML সত্যিই লাগলে আগে sanitize (যেমন DOMPurify).

ঝালিয়ে নিন: পর্ব ৩৭ · DOM, পর্ব ০২

ঙ-০২DOM event flow (capture, target, bubble) চিত্রসহ ব্যাখ্যা করুন। event delegation কী, কেন? (মাঝারি)

একটি click হলে event তিন ধাপে চলে: capture — window থেকে নেমে target-এর দিকে; target — যে element-এ ঘটেছে; bubble — target থেকে আবার উপরে window পর্যন্ত। addEventListener-এর তৃতীয় আর্গুমেন্ট true (বা {capture: true}) দিলে listener capture ধাপে চলে, নইলে bubble ধাপে।

          window ──────────────────────────► window
            │  ১ capture (নামা)            ▲  ৩ bubble (ওঠা)
          document                       document
            │                              ▲
          div#outer                      div#outer
            │                              ▲
            └──────► button#buy ───────────┘
                     ২ target
const outer = document.getElementById('outer');
const btn = document.getElementById('buy');
document.addEventListener('click', () => console.log('1 document — capture'), { capture: true, once: true });
outer.addEventListener('click', () => console.log('2 div — capture'), true);
btn.addEventListener('click', e => console.log('3 button — target, eventPhase =', e.eventPhase));
outer.addEventListener('click', e =>
  console.log('4 div — bubble · target =', e.target.id, '· currentTarget =', e.currentTarget.id));
document.addEventListener('click', () => console.log('5 document — bubble'), { once: true });
btn.click();

// delegation: পুরো তালিকার জন্য একটিই listener — পরে যোগ হওয়া বোতামেও কাজ করে
const menu = document.getElementById('menu');
menu.addEventListener('click', e => {
  const b = e.target.closest('button[data-item]');
  if (b && menu.contains(b)) console.log('অর্ডার:', b.dataset.item);
});
menu.insertAdjacentHTML('beforeend', '<li><button type="button" data-item="সিঙ্গারা">সিঙ্গারা</button></li>');
menu.querySelectorAll('button')[1].click();

প্রথম পাঁচ লাইন ১ থেকে ৫ ক্রমে — capture-এ নামা, target, তারপর bubble-এ ওঠা। target-এ eventPhase হলো 2 (capture = 1, bubble = 3). ৪ নম্বর লাইনে পার্থক্যটি দেখুন: target হলো যেখানে click ঘটেছে (buy), currentTarget হলো যার listener এখন চলছে (outer). document-এর listener-দুটি once দিয়ে বসানো, তাই পরের click-এ আর চলে না। শেষ লাইন অর্ডার: সিঙ্গারা — বোতামটি listener বসানোর পরে যোগ হয়েছে, তবু কাজ করেছে, কারণ click bubble হয়ে ul-এ পৌঁছায় আর সেখানে closest দিয়ে আসল বোতাম খোঁজা হয়। এটাই event delegation: হাজারটি সারির জন্য একটি listener — কম মেমরি, আর নতুন সারিতে আলাদা করে listener বসাতে হয় না। সীমা: focus-এর মতো কিছু event bubble করে না (এর বদলে focusin), আর stopPropagation ব্যবহার করলে delegation ভেঙে যায়। btn.click() দিয়ে তৈরি event-এর isTrusted false — আসল ব্যবহারকারীর click-এ true.

ঝালিয়ে নিন: পর্ব ৩৮ · bubbling আর delegation

ঙ-০৩localStorage, sessionStorage আর cookie-র পার্থক্য লিখুন। IndexedDB কখন? (সহজ)
বিষয়localStoragesessionStoragecookie
কত দিন থাকেমুছে না ফেলা পর্যন্তট্যাব বন্ধ হওয়া পর্যন্তExpires/Max-Age অনুযায়ী, না দিলে ব্রাউজার সেশন শেষে
কোথায় দেখা যায়একই origin-এর সব ট্যাবশুধু ওই ট্যাবনিয়ম মেলা সব request-এ সার্ভারে যায়
আকার (মোটামুটি)প্রতি origin কয়েক MB (ব্রাউজারভেদে)কয়েক MBপ্রতি cookie প্রায় ৪ KB
সার্ভারে নিজে যায়?নানাহ্যাঁ — প্রতিটি request-এ
JavaScript পড়তে পারে?হ্যাঁহ্যাঁপারে, যদি না HttpOnly
APIsynchronous, শুধু stringsynchronous, শুধু stringdocument.cookie string, বা সার্ভারের Set-Cookie

IndexedDB: বড়, গঠনযুক্ত ডেটা (object, Blob), index দিয়ে খোঁজা, transaction, asynchronous API — অফলাইন অ্যাপ বা হাজার রেকর্ডের জন্য। নিরাপত্তার নিয়ম: login token localStorage-এ রাখলে XSS হলে যেকোনো script তা চুরি করতে পারে; সেশনের জন্য HttpOnly; Secure; SameSite cookie ভালো। পছন্দের থিম বা খসড়ার মতো ক্ষতিহীন ডেটা localStorage-এ ঠিক আছে — সবসময় try/catch-এ, কারণ private mode বা ভরা storage-এ error আসতে পারে।

ঝালিয়ে নিন: পর্ব ৪০ · localStorage, cookie আর IndexedDB

ঙ-০৪client-side validation থাকলে server-side validation কেন লাগে? (সহজ)

client-side validation (required, type="email", pattern, Constraint Validation API, নিজের JavaScript) ব্যবহারকারীর সুবিধার জন্য — সাথে সাথে বার্তা, অপ্রয়োজনীয় request কম। কিন্তু এটি নিরাপত্তা নয়: কেউ DevTools-এ JavaScript বন্ধ করে, HTML বদলে, বা curl দিয়ে সরাসরি API ডেকে সব এড়াতে পারে। তাই server-side validation বাধ্যতামূলক — দাম, পরিমাণ, অনুমতি সার্ভারেই আবার যাচাই হবে, আর দাম কখনো client থেকে নেওয়া হবে না। নিয়মটি মনে রাখুন: “client-কে বিশ্বাস নয়; client-এর যাচাই শুধু UX”.

ঝালিয়ে নিন: পর্ব ৩৯ · form আর validation

ঙ-০৫XSS কী? তিন ধরন আর প্রতিরোধের উপায় লিখুন। CSP কী করে? (মাঝারি)

সংজ্ঞা: XSS (cross-site scripting) হলো আক্রমণকারীর দেওয়া লেখা পাতায় script হিসেবে চলে যাওয়া — তখন সেটি ব্যবহারকারীর নামে যা খুশি করতে পারে (ডেটা পড়া, request পাঠানো)। ধরন: stored (ডেটাবেসে রাখা মন্তব্য সবার পাতায় চলে), reflected (URL-এর অংশ সার্ভার উত্তরে ফিরিয়ে দেয়), DOM-based (ব্রাউজারের JavaScript নিজেই location.hash-এর মতো উৎস থেকে innerHTML-এ লেখে)।

প্রতিরোধ (স্তরে স্তরে): (১) ব্যবহারকারীর লেখা textContent দিয়ে বসানো, বা প্রসঙ্গ অনুযায়ী escape — framework (React, Vue) এটি ডিফল্টে করে, যতক্ষণ না আপনি dangerouslySetInnerHTML বা v-html ব্যবহার করেন; (২) HTML সত্যিই লাগলে sanitize; (৩) CSP (Content-Security-Policy header) — কোন উৎসের script চলতে পারবে তা ব্রাউজারকে বলে দেয়, inline script ডিফল্টে আটকায়; কোনো ফাঁক থেকে গেলেও ক্ষতি সীমিত করে; (৪) session cookie HttpOnly, যাতে script পড়তে না পারে। উপসংহার: CSP দ্বিতীয় দেয়াল, প্রথম দেয়াল সঠিক output encoding.

ঝালিয়ে নিন: পর্ব ৪৩ · XSS আর CSP

ঙ-০৬CORS কী? preflight request চিত্রসহ ব্যাখ্যা করুন। (কঠিন)

পটভূমি: same-origin policy অনুযায়ী এক origin-এর (scheme + host + port) পাতার JavaScript অন্য origin-এর উত্তর পড়তে পারে না। CORS হলো সার্ভারের পক্ষ থেকে নিয়ন্ত্রিত ছাড় — উত্তরে Access-Control-Allow-Origin header দিয়ে সার্ভার বলে “এই origin আমার উত্তর পড়তে পারবে”। “সাধারণ” নয় এমন request-এ (যেমন PUT/DELETE, Content-Type: application/json, বা Authorization-এর মতো নিজের header) ব্রাউজার আগে একটি preflight পাঠায়:

 ব্রাউজার (https://shop.example)              API (https://api.example)
   │ ১ OPTIONS /orders                            │
   │   Origin: https://shop.example               │
   │   Access-Control-Request-Method: PUT         │
   │   Access-Control-Request-Headers: content-type│
   │ ────────────────────────────────────────────►│
   │ ২ 204                                        │
   │   Access-Control-Allow-Origin: https://shop.example
   │   Access-Control-Allow-Methods: GET, PUT     │
   │   Access-Control-Allow-Headers: content-type │
   │   Access-Control-Max-Age: 600                │
   │ ◄────────────────────────────────────────────│
   │ ৩ আসল PUT /orders (অনুমতি মিললে)             │
   │ ────────────────────────────────────────────►│
   │ ৪ 200 + Access-Control-Allow-Origin          │
   │ ◄──────────────────────────────────────────── │  → JavaScript উত্তর পড়তে পারে

মূল কথাগুলো: “simple request” (GET/HEAD/POST, সাধারণ header, আর form বা text/plain ধরনের Content-Type) preflight ছাড়াই যায়। cookie পাঠাতে credentials: 'include' দিলে সার্ভারকে Access-Control-Allow-Credentials: true আর নির্দিষ্ট origin দিতে হয় — * চলবে না। Max-Age preflight-এর ফল কিছুক্ষণ মনে রাখে। ভুল ধারণা: CORS সার্ভারকে রক্ষা করে না — এটি ব্রাউজার প্রয়োগ করে; curl বা অন্য সার্ভার সরাসরি API ডাকতে পারে। তাই authentication আর authorization আলাদা করে লাগবেই। CORS error সারাতে হয় সার্ভারের header ঠিক করে, client-এ mode: 'no-cors' দিয়ে নয় (তাতে উত্তর পড়াই যায় না)।

ঝালিয়ে নিন: পর্ব ৪৩ · CORS, পর্ব ৩৫

ঙ-০৭process আর thread-এর পার্থক্য লিখুন। JavaScript single-threaded হলে Web Worker কী? (মাঝারি)
বিষয়processthread
সংজ্ঞাচলমান একটি প্রোগ্রাম, OS-এর দেওয়া নিজস্ব মেমরি এলাকা নিয়েprocess-এর ভেতরে কাজের একটি ধারা
মেমরিঅন্য process থেকে আলাদাএকই process-এর thread-রা heap ভাগ করে
যোগাযোগIPC — pipe, socket, messageভাগ করা মেমরি (তাই lock বা সতর্কতা লাগে)
তৈরির খরচবেশিকম
একটি ভেঙে পড়লেঅন্যগুলো সাধারণত টিকে থাকেপুরো process পড়ে যেতে পারে

JavaScript-এর কোড একটি thread-এ চলে (main thread), কিন্তু ব্রাউজার নিজে বহু thread আর process ব্যবহার করে (নেটওয়ার্ক, rendering; Chrome-এর মতো ব্রাউজারে সাধারণত প্রতিটি সাইট আলাদা process-এ)। Web Worker একটি আলাদা thread-এ আলাদা JavaScript পরিবেশ চালায় — নিজের event loop, কিন্তু DOM নেই; main thread-এর সাথে কথা হয় postMessage-এ (ডেটা কপি হয় structured clone দিয়ে, বা transfer হয়)। ভারী হিসাব (ছবি প্রক্রিয়া, বড় CSV) worker-এ দিলে পাতা জমে না। Node-এ সমতুল্য: worker_threads; আলাদা process চাইলে child_process.

ঝালিয়ে নিন: পর্ব ৪২ · Web Worker, পর্ব ৪৯ · process

ঙ-০৮service worker কী? PWA-তে cache-first আর network-first কৌশলের পার্থক্য লিখুন। (মাঝারি)

service worker হলো পাতা আর নেটওয়ার্কের মাঝখানে বসা একটি বিশেষ worker script — পাতার fetch request ধরে নিজের নিয়মে উত্তর দিতে পারে (cache থেকে, নেটওয়ার্ক থেকে, বা দুটি মিলিয়ে)। পাতা বন্ধ থাকলেও push বা background sync-এর জন্য জাগতে পারে। শুধু HTTPS-এ চলে (localhost ব্যতিক্রম); জীবনচক্র: register → install (precache) → activate (পুরোনো cache মোছা) → fetch ধরা।

কৌশল: cache-first — আগে cache, না পেলে নেটওয়ার্ক; দ্রুত আর অফলাইনে চলে, কিন্তু পুরোনো ডেটা দেখাতে পারে — ফন্ট, লোগো, version-যুক্ত CSS/JS-এর জন্য। network-first — আগে নেটওয়ার্ক, ব্যর্থ হলে cache; সবসময় সর্বশেষ ডেটা, ধীর নেটওয়ার্কে দেরি — দাম, অর্ডারের অবস্থার জন্য। stale-while-revalidate — cache থেকে সাথে সাথে দেখায়, পেছনে নেটওয়ার্ক থেকে হালনাগাদ করে রাখে। ভুল কৌশলের বিপদ: পুরোনো service worker পুরোনো অ্যাপ আটকে রাখতে পারে — তাই cache-এর নামে version রাখুন।

ঝালিয়ে নিন: পর্ব ৪৪ · PWA আর service worker

ঙ-০৯CSRF কী? SameSite cookie কীভাবে তা ঠেকায়? (মাঝারি)

CSRF (cross-site request forgery): ব্রাউজার cookie নিজে থেকে request-এর সাথে জুড়ে দেয়, request অন্য সাইটের পাতা থেকে শুরু হলেও। তাই আপনি ব্যাংকে লগইন থাকা অবস্থায় একটি খারাপ সাইট লুকানো form দিয়ে ব্যাংকে “টাকা পাঠাও” POST পাঠালে, সেটি আপনার cookie নিয়েই যায়। প্রতিরোধ: session cookie-তে SameSite=Lax বা Strict — অন্য সাইট থেকে শুরু হওয়া POST-এ cookie যায় না (আধুনিক Chromium ব্রাউজারে SameSite না দিলে Lax ধরা হয়); অবস্থা বদলানো কাজ কখনো GET-এ নয়; দরকার হলে CSRF token; আর সার্ভারে Origin header যাচাই। token যদি Authorization header-এ যায় (cookie-তে নয়), ব্রাউজার তা নিজে জোড়ে না, তাই CSRF-এর ঝুঁকি থাকে না — কিন্তু তখন token রাখার জায়গা XSS থেকে বাঁচাতে হয়।

ঝালিয়ে নিন: পর্ব ৪৩ · CSRF, পর্ব ৪০ · cookie attribute

৮ · অংশ চ — পেশাদার JavaScript, Node.js ও প্রজেক্ট (মডিউল ৭)

রিভিশনের জন্য: পর্ব ৪৫, পর্ব ৪৬, পর্ব ৪৭, পর্ব ৪৮, পর্ব ৪৯, পর্ব ৫০, পর্ব ৫১, পর্ব ৫২, পর্ব ৫৩, পর্ব ৫৪, পর্ব ৫৫.

চ-০১ES module আর CommonJS-এর পার্থক্য লিখুন। (মাঝারি)
বিষয়ES module (ESM)CommonJS (CJS)
syntaximport / exportrequire() / module.exports
কখন বিশ্লেষণচালানোর আগে, স্থির (static) — তাই tree-shaking সম্ভবচালানোর সময়, যেকোনো জায়গায় require
লোডasynchronous; top-level await চলেsynchronous
export-এর মানlive binding — রপ্তানিকারক বদলালে আমদানিকারক নতুন মান দেখেrequire-এর সময়কার মানের কপি (object হলে reference)
strict modeসবসময়নিজে লিখতে হয়
কোথায়ব্রাউজার (<script type="module">) ও Node (.mjs বা "type": "module")মূলত Node-এর পুরোনো ও বর্তমান প্যাকেজ

ESM ES2015-এ মানদণ্ডে এসেছে; CommonJS এসেছিল Node-এর শুরুর দিনে, যখন ভাষায় কোনো module ছিল না। ESM-এ __dirname নেই — import.meta.url (নতুন Node-এ import.meta.dirname). নতুন প্রজেক্টে ESM ডিফল্ট ধরুন।

ঝালিয়ে নিন: পর্ব ৪৫ · ESM বনাম CommonJS

চ-০২dependencies আর devDependencies-এর পার্থক্য কী? ^1.4.2 আর ~1.4.2 মানে কী? lockfile কেন commit করবেন? (সহজ)

dependencies — অ্যাপ চালাতে যা লাগে (express, zod). devDependencies — শুধু বানাতে ও পরীক্ষায় (vitest, eslint, vite, typescript). semver: MAJOR.MINOR.PATCH — MAJOR-এ ভাঙা পরিবর্তন, MINOR-এ নতুন সুবিধা, PATCH-এ bug fix. ^1.4.2 মানে ≥1.4.2 কিন্তু <2.0.0; ~1.4.2 মানে ≥1.4.2 কিন্তু <1.5.0. (০.x-এ ^0.4.2 মানে <0.5.0.)

lockfile (package-lock.json) প্রতিটি প্যাকেজের — পরোক্ষগুলোরও — ঠিক কোন সংস্করণ বসেছে তা লিখে রাখে। commit করলে সবার যন্ত্রে আর CI-তে হুবহু একই গাছ বসে (npm ci), “আমার মেশিনে চলে” সমস্যা কমে, আর হঠাৎ কোনো দূষিত নতুন সংস্করণ নিজে থেকে ঢুকে পড়ে না।

ঝালিয়ে নিন: পর্ব ৪৬ · npm, Vite, ESLint

চ-০৩TypeScript কেন ব্যবহার করবেন? type কি রানটাইমে থাকে? any আর unknown-এর পার্থক্য লিখুন। (মাঝারি)

TypeScript হলো JavaScript-এর ওপর static type যোগ করা একটি superset; type-checker কোড চালানোর আগে ভুল ধরে — ভুল property-র নাম, undefined হতে পারে এমন মান, ভুল আর্গুমেন্ট। বড় কোডবেসে refactor নিরাপদ হয়, editor-এ ভালো autocomplete আসে। কিন্তু type রানটাইমে থাকে না — compile-এর পর মুছে যায় (type erasure). তাই API থেকে আসা ডেটা TypeScript নিজে যাচাই করে না; সেখানে zod-এর মতো রানটাইম যাচাই লাগে।

any type-checking বন্ধ করে দেয় — যা খুশি করা যায়, ভুলও। unknown মানে “কী জানি না” — ব্যবহারের আগে typeof, instanceof বা যাচাই দিয়ে টাইপ সংকুচিত (narrow) করতে হয়। তাই বাইরের ডেটা আর catch (e)-এর জন্য unknown নিরাপদ পছন্দ।

ঝালিয়ে নিন: পর্ব ৪৭ · TypeScript-এর শুরু

চ-০৪unit test, integration test আর end-to-end test-এর পার্থক্য লিখুন। (সহজ)

unit test একটি ছোট অংশ (একটি function) আলাদা করে পরীক্ষা করে — দ্রুত, অনেকগুলো; যেমন calcTotal(cart). integration test কয়েকটি অংশ একসাথে — যেমন Express route + আসল test ডেটাবেস (supertest দিয়ে)। end-to-end test আসল ব্রাউজারে ব্যবহারকারীর মতো পুরো পথ — যেমন Playwright দিয়ে “লগইন → কার্টে যোগ → অর্ডার”; সবচেয়ে বাস্তব, কিন্তু ধীর আর মাঝে মাঝে অস্থির (flaky). প্রচলিত পরামর্শ: অনেক unit, তার চেয়ে কম integration, অল্প কয়েকটি গুরুত্বপূর্ণ e2e (testing pyramid). এই কোর্সে Vitest আর Playwright দেখানো হয়েছে।

ঝালিয়ে নিন: পর্ব ৪৮ · Vitest আর Playwright

চ-০৫Node.js single-threaded হয়েও একসাথে হাজার request কীভাবে সামলায়? কখন সে আটকে যায়? (কঠিন)

Node-এ আপনার JavaScript একটি thread-এ চলে, কিন্তু I/O-এর অপেক্ষা সে নিজে করে না। নেটওয়ার্কের কাজ OS-এর asynchronous ব্যবস্থায় (Linux-এ epoll, macOS-এ kqueue, Windows-এ IOCP) দেওয়া হয়; ফাইল, dns.lookup, crypto-র কিছু কাজ আর zlib যায় libuv-এর thread pool-এ (ডিফল্ট ৪টি thread, UV_THREADPOOL_SIZE দিয়ে বদলানো যায়)। কাজ শেষ হলে callback event loop-এর সারিতে আসে। একটি request ডেটাবেসের উত্তরের অপেক্ষায় থাকার সময় thread অন্য request সামলায় — রান্নাঘরে একজন বাবুর্চি, কিন্তু চুলা অনেক।

কখন আটকায়: CPU-ভারী synchronous কাজে — বড় JSON parse, ছবি বা PDF বানানো, জটিল regex (ReDoS), readFileSync, লম্বা লুপ। তখন সব request অপেক্ষা করে। সমাধান: কাজ ছোট টুকরোয় ভাগ, worker_threads, আলাদা সার্ভিস বা queue, আর একাধিক process (cluster বা কয়েকটি instance + load balancer). মাপার উপায়: event loop lag পর্যবেক্ষণ।

ঝালিয়ে নিন: পর্ব ৪৯ · Node.js, পর্ব ৩১, পর্ব ৪২

চ-০৬একটি সাধারণ EventEmitter class লিখুন (on, off, once, emit). Node-এর built-in-এর সাথে মিলিয়ে দেখান। (মাঝারি)

পদ্ধতি: EventEmitter হলো observer pattern: event-এর নাম থেকে listener-এর তালিকার একটি Map. on তালিকায় যোগ করে, off সরায়, emit সবাইকে ক্রমে ডাকে আর listener ছিল কি না ফেরত দেয়। once একটি মোড়ক বসায়, যা প্রথমবার চলেই নিজেকে সরিয়ে নেয়।

const { EventEmitter } = require('node:events');
class MiniEmitter {
  #handlers = new Map();                               // event-এর নাম → listener-এর তালিকা
  on(evt, fn) {
    if (!this.#handlers.has(evt)) this.#handlers.set(evt, []);
    this.#handlers.get(evt).push(fn);
    return this;                                       // chaining-এর জন্য
  }
  off(evt, fn) {
    const list = this.#handlers.get(evt) ?? [];
    this.#handlers.set(evt, list.filter(h => h !== fn && h.orig !== fn));
    return this;
  }
  once(evt, fn) {
    const wrapper = (...args) => { this.off(evt, wrapper); fn(...args); };
    wrapper.orig = fn;                                 // off(evt, fn) দিয়েও সরানো যাবে
    return this.on(evt, wrapper);
  }
  emit(evt, ...args) {
    const list = this.#handlers.get(evt) ?? [];
    for (const h of [...list]) h(...args);             // কপির ওপর লুপ: চলার মাঝে তালিকা বদলালেও নিরাপদ
    return list.length > 0;
  }
}
for (const E of [MiniEmitter, EventEmitter]) {
  const shop = new E();
  const log = id => console.log(`${E.name}: order ${id}`);
  shop.on('order', log).once('order', id => console.log(`${E.name}: first-order bonus ${id}`));
  console.log(shop.emit('order', 101), shop.emit('order', 102));
  shop.off('order', log);
  console.log(shop.emit('order', 103));
}

দুটি class-ই হুবহু একই আউটপুট দেয়: order 101, first-order bonus 101, order 102, তারপর true true, শেষে false. লক্ষ করুন true true তিনটি listener-লাইনের পরে ছাপা হয় — কারণ console.log-এর আর্গুমেন্ট (দুটি emit) আগে পুরো হিসাব হয়, আর emit synchronous: listener-রা সাথে সাথে চলে, পরের tick-এ নয়। bonus একবারই এসেছে (once). off-এর পর কোনো listener নেই, তাই emit false. [...list]-এর কপির ওপর লুপ চালানো হয়েছে, কারণ কোনো listener চলার মাঝে on দিয়ে নতুন listener যোগ করলে (যা একই array-তে push করে) আসল তালিকার ওপর লুপ অপ্রত্যাশিত আচরণ করতে পারত; off নতুন array বানায় বলে once নিজেকে সরালেও চলমান লুপ ভাঙে না — এমন edge case লিখলে পরীক্ষক বোঝেন আপনি গভীরে ভেবেছেন। Node-এর আসল EventEmitter আরও করে: listener না থাকা 'error' event emit করলে error ছোড়ে, আর একটি event-এ ১০টির বেশি listener হলে সম্ভাব্য memory leak-এর সতর্কবার্তা দেয়।

ঝালিয়ে নিন: পর্ব ৪৯, পর্ব ৩২, পর্ব ৩৮ · custom event

চ-০৭Express-এ একটি request middleware-এর ভেতর দিয়ে কীভাবে যায়? চিত্র ও কোডসহ ব্যাখ্যা করুন। (কঠিন)

সংজ্ঞা: middleware হলো (req, res, next) আকারের function, যা একটি সারিতে সাজানো থাকে। প্রতিটি হয় উত্তর দিয়ে শেষ করে (res.json(…)), নয়তো next() ডেকে পরেরটিকে দেয়। next(err) ডাকলে বাকি সাধারণ middleware বাদ দিয়ে সরাসরি error middleware-এ যায় — Express-এ যার চারটি parameter: (err, req, res, next).

 request ─► [logger] ─► [json parser] ─► [auth] ─► [validate] ─► [route handler] ─► response
                                           │ token নেই                 │ next(err)
                                           ▼                           ▼
                                       401 response              [error middleware] ─► 500

নিচে Express ছাড়া, Node-এর http module দিয়ে একই ব্যবস্থার ছোট নকল — আসল সার্ভার, আসল request:

const http = require('node:http');
const stack = [];                                      // Express-এর app.use()-এর ছোট নকল
const use = fn => stack.push(fn);
use((req, res, next) => { console.log('  [1] logger:', req.method, req.url); next(); });
use((req, res, next) => {
  if (req.headers.authorization !== 'Bearer demo') return res.writeHead(401).end('token নেই'); // next() নয়
  console.log('  [2] auth: ঠিক আছে'); next();
});
use((req, res, next) => (req.url === '/boom' ? next(new Error('DB বন্ধ')) : next()));
use((req, res) => {
  console.log('  [3] route handler');
  res.writeHead(200, { 'Content-Type': 'application/json' }).end(JSON.stringify({ ok: true }));
});
const onError = (err, req, res) => {
  console.log('  [E] error middleware:', err.message);
  res.writeHead(500).end('সার্ভারে সমস্যা');
};
const server = http.createServer((req, res) => {
  let i = 0;
  (function next(err) { err ? onError(err, req, res) : stack[i++]?.(req, res, next); })();
});
const get = (path, headers) => new Promise(done => {
  http.get({ host: '127.0.0.1', port: server.address().port, path, headers }, res => {
    let body = '';
    res.setEncoding('utf8').on('data', c => (body += c)).on('end', () => done(`${res.statusCode} ${body}`));
  });
});
server.listen(0, '127.0.0.1', async () => {
  for (const [path, auth] of [['/products', 'Bearer demo'], ['/products', ''], ['/boom', 'Bearer demo']]) {
    console.log('GET', path, auth ? '(token সহ)' : '(token ছাড়া)');
    console.log('  ->', await get(path, auth ? { authorization: auth } : {}));
  }
  server.close();
});

প্রথম request সব ধাপ পেরিয়ে -> 200 {"ok":true}. দ্বিতীয়টি token ছাড়া — logger চলে, auth সেখানেই 401 token নেই দিয়ে শেষ করে; route handler আর চলেই না। তৃতীয়টি auth পেরোয়, কিন্তু তৃতীয় middleware next(new Error(…)) ডাকে, তাই route handler বাদ দিয়ে error middleware 500 সার্ভারে সমস্যা দেয়। মূল শিক্ষা: ক্রমই নিয়ম — auth-এর আগে বসানো route সুরক্ষিত নয়; আর একটি middleware যদি উত্তরও না দেয়, next()-ও না ডাকে, request ঝুলে থাকে। Express 4-এ async handler-এর rejected Promise নিজে থেকে error middleware-এ যায় না (next(err) নিজে ডাকতে হয়); Express 5 এটি নিজেই ধরে। listen(0) OS-কে একটি খালি port বেছে নিতে বলে।

ঝালিয়ে নিন: পর্ব ৫০ · Express দিয়ে REST API, পর্ব ৪৯

চ-০৮REST আর GraphQL-এর পার্থক্য লিখুন। REST-এ HTTP method আর status code কীভাবে বাছবেন? (মাঝারি)
বিষয়RESTGraphQL
endpointপ্রতিটি resource-এর আলাদা URL — /products/7সাধারণত একটি — /graphql
কী ডেটা আসেসার্ভার ঠিক করে — বেশি বা কম আসতে পারেclient query-তে ঠিক যে field চায়, তাই
একাধিক resourceপ্রায়ই কয়েকটি requestএকটি query-তে nested ডেটা
HTTP cacheসহজ — GET আর URL দিয়েকঠিন — সাধারণত POST, আলাদা cache ব্যবস্থা
errorHTTP status codeপ্রায়ই 200 + উত্তরে errors array
ঝুঁকিover-fetching, version ব্যবস্থাপনাখুব গভীর বা ভারী query — depth/cost সীমা লাগে; N+1 query

REST-এর নিয়ম: GET পড়া (নিরাপদ, idempotent), POST নতুন তৈরি (idempotent নয়), PUT পুরোটা বদল (idempotent), PATCH আংশিক বদল, DELETE মোছা (idempotent). status code: 200 ঠিক আছে, 201 তৈরি হলো (সাথে Location), 204 উত্তরে কিছু নেই, 400 ভুল অনুরোধ, 401 পরিচয় নেই, 403 অনুমতি নেই, 404 পাওয়া যায়নি, 409 সংঘর্ষ (যেমন স্টক শেষ), 422 যাচাই ব্যর্থ, 429 খুব বেশি অনুরোধ, 500 সার্ভারের ভুল। উপসংহার: ছোট-মাঝারি API আর সর্বজনীন API-তে REST সহজ; অনেক ধরনের client আর জটিল nested ডেটায় GraphQL সুবিধা দেয়।

ঝালিয়ে নিন: পর্ব ৫০, পর্ব ৩৫

চ-০৯SQL injection কী? parameterized query কীভাবে ঠেকায়? transaction আর ACID সংক্ষেপে লিখুন। (মাঝারি)

SQL injection: ব্যবহারকারীর ইনপুট string জোড়া দিয়ে SQL বানালে ইনপুটটিই SQL-এর অংশ হয়ে যায়। `SELECT * FROM users WHERE email = '${email}'`-এ কেউ ' OR '1'='1 দিলে শর্ত সবসময় সত্য। parameterized query-তে SQL আর মান আলাদা যায় — db.query('SELECT * FROM users WHERE email = $1', [email]) — ডেটাবেস মানকে কখনো SQL হিসেবে পড়ে না। সীমা: table বা column-এর নাম parameter দিয়ে দেওয়া যায় না — সেগুলো allowlist থেকে বাছুন। ORM বা query builder সাধারণত নিজে parameter ব্যবহার করে, কিন্তু raw query-তে আবার দায় আপনার।

transaction: কয়েকটি কাজ একসাথে — হয় সব হবে, নয় কিছুই না (অর্ডার তৈরি + স্টক কমানো)। ACID: Atomicity (সব বা কিছু না), Consistency (নিয়ম ভাঙে না), Isolation (একসাথে চলা transaction একে অপরকে বিভ্রান্ত করে না), Durability (commit হলে বিদ্যুৎ গেলেও থাকে)।

ঝালিয়ে নিন: পর্ব ৫২ · Node.js আর ডেটাবেস

চ-১০polling, WebSocket আর Server-Sent Events-এর পার্থক্য লিখুন। কোনটি কখন? (মাঝারি)

polling: client কিছুক্ষণ পরপর জিজ্ঞেস করে “নতুন কিছু?” — সহজ, কিন্তু বেশিরভাগ request খালি আর দেরি থাকে। SSE (EventSource): সার্ভার থেকে client-এ একমুখী ধারা, সাধারণ HTTP-র ওপর; সংযোগ ভাঙলে ব্রাউজার নিজেই আবার যোগ করে (Last-Event-ID দিয়ে)। শুধু লেখা (text) পাঠায়। অর্ডারের অবস্থা, নোটিফিকেশন, লাইভ স্কোরের জন্য যথেষ্ট — ক্যাপস্টোনে অর্ডারের লাইভ অবস্থা SSE-তে। WebSocket: একটি দীর্ঘস্থায়ী দুমুখী (full-duplex) সংযোগ, HTTP থেকে upgrade করে; text ও binary — চ্যাট, যৌথ সম্পাদনা, multiplayer গেম। খরচ: সংযোগ ধরে রাখা, পুনঃসংযোগ, heartbeat আর একাধিক সার্ভারে ছড়ানোর ব্যবস্থা নিজেকে করতে হয়। নিয়ম: সার্ভার থেকে শুধু পাঠানো → SSE; দুই দিক থেকে ঘন ঘন → WebSocket; খুব বিরল হালনাগাদ → polling-ই যথেষ্ট।

ঝালিয়ে নিন: পর্ব ৫১ · WebSocket আর SSE

চ-১১JavaScript-এ memory leak কীভাবে হয়? চারটি সাধারণ উৎস আর খোঁজার উপায় লিখুন। (মাঝারি)

garbage collector শুধু সেই object মোছে, যাতে root (global, stack) থেকে আর পৌঁছানো যায় না। memory leak মানে অপ্রয়োজনীয় object কোনো এক reference-এর কারণে পৌঁছানো যায় — তাই মুছতে পারে না। সাধারণ উৎস: (১) সরানো হয়নি এমন event listener বা setInterval, যার closure বড় ডেটা ধরে আছে; (২) চিরকাল বাড়তে থাকা cache বা global array/Map; (৩) DOM থেকে সরানো, কিন্তু JavaScript-এর variable-এ রাখা node (detached DOM); (৪) SPA-তে পাতা বদলের পরও চলতে থাকা subscription (WebSocket, observer). খোঁজা: DevTools-এর Memory প্যানেলে একই কাজ কয়েকবার করে heap snapshot নিন, তুলনা করুন — যে object বাড়তেই থাকে তার retaining path দেখায় কে তাকে ধরে আছে। প্রতিরোধ: removeEventListener বা AbortController-এর signal, আকার-সীমিত cache, WeakMap.

ঝালিয়ে নিন: পর্ব ৫৩ · memory leak আর DevTools

চ-১২SSR আর CSR-এর পার্থক্য লিখুন। SSG আর hydration কী? (মাঝারি)
বিষয়CSR (client-side rendering)SSR (server-side rendering)
HTML কে বানায়ব্রাউজারে JavaScript, প্রায় খালি HTML থেকেপ্রতিটি request-এ সার্ভার
প্রথম লেখা দেখাJavaScript নামা ও চলার পরে — ধীর ফোনে দেরিদ্রুত — HTML-এ আগেই লেখা
SEO ও link previewদুর্বল হতে পারেভালো
সার্ভারের খরচকম — static ফাইলবেশি — প্রতি request-এ render
পরের পাতা বদলদ্রুত, পুরো পাতা না এনেframework-ভেদে, প্রায়ই client-side routing-এর সাথে মেশানো
উপযুক্তলগইনের পরের ড্যাশবোর্ড, admin panelদোকানের পণ্যের পাতা, খবর, যেখানে SEO জরুরি

SSG (static site generation): build-এর সময়ই HTML বানিয়ে রাখা — সবচেয়ে দ্রুত আর সস্তা, কিন্তু ডেটা বদলালে আবার build লাগে (ব্লগ, ডকুমেন্টেশন)। hydration: SSR বা SSG-এর HTML ব্রাউজারে পৌঁছানোর পর framework-এর JavaScript সেই HTML-এ event listener আর state জুড়ে তাকে interactive করে। খরচ: লেখা দেখা যায়, কিন্তু hydration শেষ না হওয়া পর্যন্ত বোতাম কাজ নাও করতে পারে — তাই islands বা streaming SSR-এর মতো কৌশল এসেছে। বাস্তবে আধুনিক meta-framework একই অ্যাপে পাতাভেদে কৌশল মেশায়।

ঝালিয়ে নিন: পর্ব ৫৪ · React, Vue, Svelte, পর্ব ০২

৯ · ভাইভায় কথা বলার কৌশল, নিজের প্রজেক্ট আর দ্রুত প্রশ্ন

লিখিত পরীক্ষায় আপনি ভাবার সময় পান, কাটাকাটি করতে পারেন। ভাইভায় পারেন না — প্রশ্ন আসে মুখে, উত্তরও দিতে হয় তখনই। আর পরীক্ষক আপনার প্রথম উত্তর শুনেই পরের প্রশ্ন বানান। এমন প্রশ্নকে বলে follow-up প্রশ্ন. তাই ভাইভার আসল দক্ষতা দুটি: ছোট, গোছানো উত্তর, আর প্রশ্নের শিকল সামলানো।

তিন বাক্যের কাঠামো: সংজ্ঞা → উদাহরণ → সুবিধা বা সীমা

সংজ্ঞা (এক বাক্য) → উদাহরণ (এক বাক্য) → সুবিধা, সীমা বা সতর্কতা (এক বাক্য)

প্রশ্ন: “Promise কী?” দুর্বল উত্তর: “Promise হলো… মানে… async… then দিয়ে… আর resolve…”. গোছানো উত্তর: “Promise হলো ভবিষ্যতে আসবে এমন একটি মানের প্রতিনিধি object — pending থেকে একবারই fulfilled বা rejected হয় (সংজ্ঞা)। যেমন fetch সাথে সাথে একটি Promise দেয়, উত্তর এলে then বা await দিয়ে পাই (উদাহরণ)। callback-এর চেয়ে সুবিধা হলো chain করা যায় আর একটি catch-এ সব error ধরা যায়, তবে বাতিল করতে আলাদা AbortController লাগে (সুবিধা ও সীমা)।” পনেরো সেকেন্ড, তিন বাক্য — আর পরীক্ষকের হাতে পরের প্রশ্নের তিনটি সূত্র।

ভাইভার উত্তরকে রিকশাওয়ালাকে পথ বলার মতো ভাবুন। প্রথমে গন্তব্য বলেন (“ধানমন্ডি ২৭”) — সংজ্ঞা। তারপর একটি চেনা চিহ্ন (“মসজিদের পাশের গলি”) — উদাহরণ। শেষে একটি সতর্কতা (“মিরপুর রোডে এখন জ্যাম, ভেতর দিয়ে যান”) — সীমা। পুরো শহরের মানচিত্র বোঝাতে বসলে রিকশা আর চলে না।

  • আগে উত্তর, পরে বিস্তার: পরীক্ষক চাইলে নিজেই “আরেকটু বলুন” বলবেন। নিজে থেকে পাঁচ মিনিট বললে বাকি প্রশ্নের সময় কমে, আর ভুল বলার সুযোগ বাড়ে।
  • Think aloud: নিশ্চিত না হলে ভাবনাটা জোরে বলুন — “then microtask… setTimeout task… তাই আগে then ছাপবে।” পরীক্ষক আপনার যুক্তির পথ দেখতে চান।
  • পরিবেশ স্পষ্ট করুন: “ব্রাউজারে sloppy mode-এ this হবে window, strict mode-এ undefined.” “Node 20-এ Object.groupBy নেই, Node 21 থেকে আছে।” এই সতর্কতা অভিজ্ঞতার চিহ্ন।
  • সংস্করণ বলুন: “?? আর ?. ES2020-এ, private field ES2022-এ।” আধুনিক JavaScript জানা আছে, এটা বোঝানোর সবচেয়ে সহজ উপায়।
  • বোর্ড বা কাগজ চান: “একটু এঁকে দেখাই?” — event loop বা prototype chain-এর ছবি মুখের কথার চেয়ে শক্তিশালী।

নিচের ডায়াগ্রামে একটি বাস্তবধর্মী ভাইভার শিকল দেখুন। প্রতিটি ধাপে প্রশ্ন একটু গভীরে যাচ্ছে। শেষ ধাপে প্রার্থী পুরো নিশ্চিত নন — তবু সঠিকভাবে সামলাচ্ছেন।

প্রশ্ন ১সহজ শুরু
পরীক্ষক: JavaScript single-threaded হলে setTimeout কীভাবে কাজ করে?
আপনি:   অপেক্ষাটা JavaScript করে না — ব্রাউজারের timer করে।
        সময় হলে callback একটি task queue-তে যায়, আর stack
        খালি হলে event loop সেটি চালায়। তাই 0 ms মানে "সাথে
        সাথে" নয়, "পরের সুযোগে"।
প্রশ্ন ২ফলো-আপ — দুই সারি
পরীক্ষক: তাহলে Promise.then আর setTimeout — কোনটি আগে?
আপনি:   then আগে। then যায় microtask queue-তে, setTimeout
        task queue-তে। প্রতিটি task-এর পর microtask queue
        পুরো খালি করা হয়, তারপর পরের task.
প্রশ্ন ৩ফলো-আপ — প্রয়োগ
পরীক্ষক: async function-এ await-এর আগের লাইন কখন চলে?
আপনি:   সাথে সাথে, synchronous-ভাবে — ডাকার মুহূর্তেই।
        প্রথম await-এ function থামে আর caller-কে একটি
        Promise ফেরত দেয়; বাকি অংশ পরে microtask হিসেবে চলে।
প্রশ্ন ৪ফলো-আপ — ফাঁদ
পরীক্ষক: একটি then নিজের ভেতরে আবার then যোগ করতেই থাকলে?
আপনি:   microtask queue কখনো খালি হবে না — setTimeout,
        click, এমনকি render-ও আসবে না, পাতা জমে যাবে।
        একে microtask starvation বলে। ভারী লুপ ভাগ করতে
        তাই setTimeout বা worker ভালো।
প্রশ্ন ৫কঠিন — পুরো নিশ্চিত নন
পরীক্ষক: Node-এ setImmediate আর setTimeout(fn, 0) — কোনটি আগে?
আপনি:   পুরো নিশ্চিত নই। যা জানি: Node-এর event loop কয়েকটি
        phase-এ চলে — timer phase আর check phase আলাদা,
        setImmediate check phase-এ। তাই আমার ধারণা উত্তরটা
        নির্ভর করে আমরা loop-এর কোন phase থেকে ডাকছি তার ওপর।
(ঠিক দিকেই: main script থেকে ডাকলে ক্রম নিশ্চিত নয়;
কিন্তু কোনো I/O callback-এর ভেতর থেকে ডাকলে setImmediate আগে।)
  1. সহজ শুরু। সংজ্ঞা, প্রক্রিয়া, সতর্কতা — তিন বাক্য। শেষ বাক্যটিই (“0 ms মানে সাথে সাথে নয়”) পরীক্ষককে পরের প্রশ্নের সূত্র দিল।
  2. দুই সারির প্রশ্ন। “microtask” আর “task” — দুটি শব্দ আর একটি নিয়ম (প্রতি task-এর পর সব microtask). এই নিয়মটি বললে আউটপুটের প্রায় সব প্রশ্নের উত্তর দেওয়া যায়।
  3. প্রয়োগ। async function-এর প্রথম await পর্যন্ত অংশ synchronous — অনেকেই এখানে ভুল করেন। অংশ ৬-এর event loop প্রোগ্রামের ২ নম্বর লাইন ঠিক এটাই দেখায়।
  4. ফাঁদের প্রশ্ন। starvation-এর ধারণা দেখায় আপনি শুধু নিয়ম নয়, তার পরিণতিও বোঝেন — আর সমাধানও দিলেন।
  5. “জানি না” সামলানো। প্রার্থী সৎভাবে বলছেন নিশ্চিত নন, তারপর যা জানেন (phase) তা থেকে যুক্তি দিয়ে এগোচ্ছেন — আর যুক্তিটি সঠিক দিকেই গেছে। এভাবে ভেবে বলা উত্তর প্রায়ই অন্তত আংশিক কৃতিত্ব পায়।

যে প্রশ্নের উত্তর জানেন না

  1. থামুন, প্রশ্নটি নিশ্চিত হয়ে নিন: “আপনি কি ব্রাউজারের কথা বলছেন, নাকি Node-এর?” JavaScript-এ অনেক উত্তর পরিবেশের ওপর নির্ভর করে, তাই প্রশ্নটি নিজেই জরুরি।
  2. যা জানেন সেখান থেকে শুরু করুন: “ঠিক এটা পড়িনি, তবে কাছাকাছি জিনিস জানি — …”.
  3. যুক্তি দিয়ে এগোন, জোরে: আন্দাজকে আন্দাজ বলেই বলুন — “আমার ধারণা…”.
  4. যাচাইয়ের উপায় বলুন: “নিশ্চিত হতে আমি console-এ দুই লাইনের একটি পরীক্ষা চালাতাম” — এটি একজন কাজের ডেভেলপারের উত্তর।
  5. না পারলে সৎভাবে বলুন, আর এগিয়ে যান: “এটা আমি জানি না, পরে দেখে নেব।” আন্দাজে ভুল তথ্য জোর দিয়ে বললে পরীক্ষক আপনার বাকি ঠিক উত্তরগুলো নিয়েও সন্দেহ করেন। আর একটি প্রশ্ন না পারা পুরো ভাইভা নয়।

নিজের প্রজেক্ট নিয়ে কথা বলা

প্রায় সব ভাইভা আর ইন্টারভিউতে একটি প্রশ্ন আসে: “আপনার একটি প্রজেক্টের কথা বলুন।” এই কোর্সে আপনার দুটি প্রজেক্ট আছে — পর্ব ২১-এর মাঝপথের প্রজেক্ট “হিসাব খাতা” (ব্রাউজারে খরচের খাতা: pure function-এর core, পাতলা DOM স্তর, undo, পয়সায় টাকা) আর পর্ব ৫৫-এর ক্যাপস্টোন “দোকানঘর” (Vite-এ front end, Express-এ API, PostgreSQL, লগইন, SSE-তে অর্ডারের লাইভ অবস্থা, টেস্ট, CI আর deploy). একটি প্রচলিত কাঠামো হলো STAR: Situation (প্রেক্ষাপট), Task (আপনার দায়িত্ব), Action (কী করলেন), Result (ফল)।

অংশকী বলবেন“দোকানঘর”-এর উদাহরণ
৩০ সেকেন্ডের পরিচয়কী সমস্যা, কার জন্য, কোন প্রযুক্তি“ছোট দোকানের অনলাইন অর্ডারের full-stack অ্যাপ — Vite, Express, PostgreSQL, live অর্ডার-অবস্থা SSE-তে।”
একটি নকশার সিদ্ধান্তকী বেছে নিয়েছেন, কেন, বিকল্প কী ছিল“লাইভ অবস্থায় WebSocket নয়, SSE — কারণ তথ্য শুধু সার্ভার থেকে আসে, আর SSE নিজে পুনঃসংযোগ করে।”
একটি কঠিন সমস্যাকী ভাঙছিল, কীভাবে ধরলেন, কীভাবে সারালেন“শেষ পিসটি দুজন একসাথে কিনতে পারত — অর্ডার আর স্টক কমানো একটি transaction-এ এনে, টেস্ট লিখে ঠিক করেছি।”
প্রমাণটেস্ট, README, live link“ব্যবসার নিয়ম আলাদা service-এ, তাই HTTP ছাড়াই টেস্ট চলে; CI-তে প্রতি push-এ চলে।”
আবার করলেকী ভিন্নভাবে করতেন“শুরু থেকেই TypeScript আর অর্ডারে idempotency key রাখতাম।”

প্রজেক্টের যে অংশ আপনি নিজে বোঝেন না — হয়তো AI বা বন্ধু লিখে দিয়েছে — সেটি নিয়ে বড় দাবি করবেন না। পরীক্ষকেরা প্রায়ই ঠিক সেই লাইন ধরে জিজ্ঞেস করেন: “এখানে useEffect-এর dependency array খালি কেন?”, “এই route-এ auth middleware কোথায়?”, “এই query-তে parameter আছে?” নিজের প্রজেক্টের প্রতিটি সিদ্ধান্তের কারণ নিজের ভাষায় বলতে পারা — এটাই সবচেয়ে বড় প্রস্তুতি।

জুনিয়র ডেভেলপার পদের HR-ধাঁচের টেকনিক্যাল প্রশ্ন

এগুলোর কোনো একমাত্র “সঠিক” উত্তর নেই; পরীক্ষক দেখেন আপনি সৎ, গোছানো আর শিখতে আগ্রহী কি না। নিচের উত্তরগুলো কাঠামোর নমুনা — নিজের অভিজ্ঞতা দিয়ে ভরাবেন।

এই-০১দুই মিনিটে নিজের পরিচয় দিন — টেকনিক্যাল দিক থেকে। (সহজ)

তিন অংশ: এখন — “আমি JavaScript দিয়ে web অ্যাপ বানাই, মূলত front end, Node-এ ছোট API-ও লিখেছি।” প্রমাণ — একটি প্রজেক্ট আর তার একটি সংখ্যা বা ফল (“দোকানঘর: ৭টি মাইলস্টোন, টেস্ট ও CI-সহ deploy করা”)। সামনে — এই পদের সাথে মিল (“আপনাদের দলে আসল ব্যবহারকারীর জন্য পণ্য বানাতে চাই”)। জীবনী নয়, সিভি পড়ে শোনানো নয়।

এই-০২কেন JavaScript, আর কেন front end (বা back end)? (সহজ)

একটি সত্যিকারের কারণ, একটি টেকনিক্যাল যুক্তি: “ব্যবহারকারী সাথে সাথে ফল দেখেন, সেটা আমাকে টানে; আর এক ভাষায় ব্রাউজার, সার্ভার, এমনকি মোবাইলেও কাজ করা যায়।” সাথে সীমাও স্বীকার করুন — “dynamic typing-এর ঝুঁকির জন্য TypeScript শিখছি” — এতে পরিপক্বতা বোঝা যায়।

এই-০৩একটি কঠিন bug-এর কথা বলুন — কীভাবে খুঁজলেন, কীভাবে সারালেন? (মাঝারি)

STAR মেনে: লক্ষণ (“search-এ মাঝে মাঝে পুরোনো ফল দেখাত”), কীভাবে পুনরুৎপাদন করলেন (Network প্যানেলে throttling), কারণ (ধীর পুরোনো উত্তর নতুনটির পরে আসছিল — race condition), সমাধান (debounce + AbortController দিয়ে পুরোনো অনুরোধ বাতিল), আর শিক্ষা (এখন async UI-তে প্রথমেই এই প্রশ্ন করি)। প্রমাণভিত্তিক debugging-এর পদ্ধতি দেখানোই এখানে আসল।

এই-০৪framework তো প্রতি বছর বদলায় — নতুন technology কীভাবে শেখেন? (মাঝারি)

একটি পদ্ধতি বলুন: অফিসিয়াল ডকুমেন্টেশন আর tutorial → একটি ছোট নিজের প্রজেক্ট → যে অংশ বুঝিনি তার মূল ধারণায় ফেরা (React শিখতে গিয়ে closure আর immutable update). যোগ করুন, ভাষার ভিত্তি — event loop, closure, HTTP — বদলায় না, তাই নতুন framework দ্রুত ধরা যায়। সাম্প্রতিক একটি উদাহরণ দিলে উত্তর বিশ্বাসযোগ্য হয়।

এই-০৫কাজে AI coding tool কীভাবে ব্যবহার করেন? (মাঝারি)

সৎ ও দায়িত্বশীল উত্তর: “কাঠামো, টেস্টের খসড়া, অপরিচিত API বুঝতে ব্যবহার করি; কিন্তু প্রতিটি লাইন পড়ি, চালাই, টেস্ট দিয়ে যাচাই করি, আর কোনো secret বা গ্রাহকের ডেটা দিই না। প্রতিষ্ঠানের নীতি থাকলে সেটাই মানি।” একটি উদাহরণ দিন যেখানে AI ভুল করেছিল আর আপনি ধরেছেন — যেমন সন্দেহজনক বা অস্তিত্বহীন npm প্যাকেজের নাম প্রস্তাব করা।

এই-০৬deadline-এর চাপে কোডের মান নিয়ে কী করবেন? (মাঝারি)

ভারসাম্যের উত্তর: আগে দলকে জানানো — কী সময়ে হবে, কী বাদ দিলে হবে। নিরাপত্তা, ডেটার সঠিকতা আর টেস্ট-ছাড়া টাকার হিসাব — এগুলোতে আপস নয়। সৌন্দর্যের refactor পরে করা যায়, কিন্তু সেটা লিখিত “technical debt” হিসেবে ticket-এ রাখি, যাতে হারিয়ে না যায়।

এই-০৭code review-তে কেউ আপনার কোডের কড়া সমালোচনা করলে? (সহজ)

সমালোচনা কোডের, আমার নয় — এই মনোভাব দেখান। কারণ জিজ্ঞেস করি, যুক্তি ঠিক হলে বদলাই আর ধন্যবাদ দিই; দ্বিমত থাকলে প্রমাণ দিয়ে (benchmark, ডকুমেন্টেশন, টেস্ট) আলোচনা করি, আর দলের সিদ্ধান্ত মানি। একটি বাস্তব উদাহরণ দিন, যেখানে review থেকে কিছু শিখেছেন।

এই-০৮“আপনার কোনো প্রশ্ন আছে?” — কী জিজ্ঞেস করবেন? (সহজ)

“না” বলবেন না। কাজ নিয়ে দু–একটি আন্তরিক প্রশ্ন: দলে code review আর টেস্ট কীভাবে হয়? নতুন যোগ দেওয়া ডেভেলপারের প্রথম তিন মাস কেমন যায়? কোন stack-এ কাজ, আর কোন সমস্যাটি এখন সবচেয়ে বড়? এগুলো আগ্রহ আর পেশাদারি দেখায়।

ভাইভা কুইকফায়ার — দ্রুত প্রশ্ন ও ফলো-আপ

ভাইভায় প্রশ্ন আসে দ্রুত, উত্তরও হতে হয় এক–তিন বাক্যে। জোরে জোরে উত্তর বলুন, তারপর মেলান — প্রতিটিতে ২০ সেকেন্ডের বেশি নয়। “ফলো-আপ” লেখা প্রশ্ন আগের প্রশ্নের উত্তর থেকে জন্মানো; এগুলো পরপর পড়ুন।

ভিত্তি ও মূল ভাষা (পর্ব ০১–১৩)

ভ-০১JavaScript আর Java কি সম্পর্কিত? “ECMAScript” নাম কেন? (সহজ)

না — দুটি আলাদা ভাষা; ১৯৯৫ সালে Java-র জনপ্রিয়তার সময় বাজারজাতকরণের কারণে নাম রাখা হয়েছিল। “JavaScript” একটি trademark (এখন Oracle-এর), তাই মানদণ্ডের নাম ECMAScript — Ecma International-এর ECMA-262 নথি। পর্ব ০১

ভ-০২"use strict" কী বদলায়? (মাঝারি)

ঘোষণা ছাড়া variable-এ মান দিলে global না বানিয়ে ReferenceError; সাধারণ function call-এ this হয় undefined; চুপচাপ ব্যর্থ হওয়া কাজ (read-only property-তে লেখা) TypeError দেয়; with নিষিদ্ধ। ES module আর class-এর ভেতর নিজে থেকেই strict. পর্ব ০৭

ভ-০৩ফলো-আপ: ঘোষণাই হয়নি এমন variable-এ typeof দিলে কী হয়? (মাঝারি)

error নয় — 'undefined' দেয়; feature detection-এ এটি কাজে লাগে। ব্যতিক্রম: let/const-এর TDZ-এর ভেতরে typeof x দিলে ReferenceError. পর্ব ০৭

ভ-০৪isNaN আর Number.isNaN-এর পার্থক্য? (মাঝারি)

পুরোনো global isNaN আগে number-এ রূপান্তর করে, তাই isNaN('চা') true. Number.isNaN (ES2015) রূপান্তর করে না — শুধু সত্যিকারের NaN মানে true. পর্ব ১০

ভ-০৫'5' + 3 আর '5' - 3-এর ফল কী, কেন? (সহজ)

'53' আর 2. +-এর এক পাশে string থাকলে জোড়া লাগায় (concatenation); - শুধু সংখ্যার অপারেটর, তাই '5'-কে number-এ রূপান্তর করে। পর্ব ০৬

ভ-০৬switch কোন তুলনা ব্যবহার করে? break না দিলে কী হয়? (সহজ)

strict তুলনা (===) — তাই case 1 string '1'-এর সাথে মেলে না। break না দিলে পরের case-গুলোও চলতে থাকে (fall-through); ইচ্ছাকৃত হলে মন্তব্যে লিখুন। পর্ব ১১

ডেটা স্ট্রাকচার (পর্ব ১৪–২১)

ভ-০৭const cart = []; cart.push(1) কেন চলে? (সহজ)

const শুধু variable-কে নতুন মান দেওয়া আটকায়; সে যে array-কে দেখায় তার ভেতর বদলানো আটকায় না। cart = [] লিখলে তখন TypeError. পর্ব ০৭, পর্ব ১৫

ভ-০৮array খালি করার arr.length = 0 আর arr = []-এর পার্থক্য? (মাঝারি)

arr.length = 0 একই array-কে খালি করে — অন্য যে variable ওই array দেখে, সেও খালি দেখে। arr = [] নতুন array বানায় (variable let হতে হবে); পুরোনো reference-গুলো পুরোনো ডেটাই দেখে। পর্ব ১৫

ভ-০৯[...new Set(arr)] কী করে? ক্রম থাকে? (সহজ)

duplicate সরায়; Set ঢোকানোর ক্রম রাখে, তাই প্রতিটি মানের প্রথম উপস্থিতির ক্রম থাকে। তুলনা SameValueZero দিয়ে — NaN-ও একবারই থাকে, কিন্তু একই রকম দেখতে দুটি object আলাদা। পর্ব ১৮

ভ-১০array চেনার জন্য typeof কেন চলে না? (সহজ)

typeof [] হলো 'object'. Array.isArray(x) ব্যবহার করুন — এটি অন্য iframe-এ তৈরি array-ও চেনে, যেখানে instanceof Array ব্যর্থ হয়। পর্ব ১৫

function ও object গভীরে (পর্ব ২২–৩০)

ভ-১১IIFE কী? আজকাল কম লাগে কেন? (সহজ)

সাথে সাথে ডাকা function expression — (() => { … })() — আলাদা scope বানাতে, যাতে variable global-এ না ছড়ায়। এখন block scope (let/const) আর ES module সেই কাজ করে। পর্ব ২২

ভ-১২pure function কী? একটি উদাহরণ দিন। (সহজ)

একই ইনপুটে সবসময় একই ফল, আর বাইরের কিছু বদলায় না (side effect নেই)। (a, b) => a + b pure; Math.random() বা global counter বাড়ানো function নয়। সুবিধা: টেস্ট সহজ, memoize করা যায়। পর্ব ২৩

ভ-১৩ফলো-আপ: object-এর method হিসেবে arrow function কেন ঝুঁকিপূর্ণ? (মাঝারি)

arrow-এর নিজের this নেই; object literal-এ লেখা arrow method-এর this object নয়, বাইরের scope-এর this (module-এ undefined). তাই { total: () => this.items } ভাঙে; method shorthand total() {…} লিখুন। পর্ব ২৪

ভ-১৪Object.freeze আর const-এর পার্থক্য? freeze কি গভীর? (মাঝারি)

const variable আটকায়, Object.freeze object-এর property আটকায় (যোগ, বদল, মোছা — strict mode-এ TypeError, নইলে চুপচাপ উপেক্ষা)। freeze shallow — ভেতরের object বদলানো যায়; গভীরে আটকাতে recursive freeze লাগে। পর্ব ১৪

ভ-১৫instanceof আসলে কী পরীক্ষা করে? (মাঝারি)

x instanceof C দেখে C.prototype x-এর prototype chain-এ কোথাও আছে কি না — class-এর নাম নয়। তাই prototype বদলালে ফলও বদলায়, আর ভিন্ন realm-এর (iframe) object-এ ব্যর্থ হতে পারে। পর্ব ২৫

Asynchronous JavaScript (পর্ব ৩১–৩৬)

ভ-১৬Promise-এর executor function synchronous না asynchronous? (মাঝারি)

synchronous — new Promise(fn) লেখার মুহূর্তেই fn চলে। শুধু then/catch-এর callback পরে (microtask হিসেবে) চলে। পর্ব ৩৩

ভ-১৭ফলো-আপ: আগেই resolved একটি Promise-এ then দিলে callback কি সাথে সাথে চলে? (মাঝারি)

না — সবসময় asynchronous, বর্তমান synchronous কোড শেষ হওয়ার পর microtask হিসেবে। এই নিশ্চয়তা আছে বলেই callback কখনো “কখনো sync, কখনো async” আচরণ করে না। পর্ব ৩৩, পর্ব ৩১

ভ-১৮await বা catch ছাড়া একটি ব্যর্থ async function ডাকলে error কোথায় যায়? (মাঝারি)

কোথাও ধরা পড়ে না — rejected Promise হয়ে থাকে, যাকে বলে unhandled rejection. ব্রাউজারে unhandledrejection event আর console-এ error; Node 15 থেকে ডিফল্টে process বন্ধ হয়ে যায়। পর্ব ৩৪

ভ-১৯throttle কোথায় ব্যবহার করবেন, debounce কোথায়? একটি করে উদাহরণ। (সহজ)

debounce — search box, window resize শেষ হলে layout হিসাব, form-এর autosave. throttle — scroll-এ অবস্থান হালনাগাদ, infinite scroll-এর পরীক্ষা, গেমে বোতাম চাপার সীমা। পর্ব ৩৬

ব্রাউজার ও DOM (পর্ব ৩৭–৪৪)

ভ-২০DOMContentLoaded আর load event-এর পার্থক্য? (সহজ)

DOMContentLoaded — HTML parse শেষ, DOM তৈরি (defer করা script চলার পর); ছবি বা stylesheet-এর অপেক্ষা নেই। load — ছবি, ফন্ট, iframe-সহ সব resource নামা শেষ। পর্ব ৩৭

ভ-২১preventDefault() আর stopPropagation()-এর পার্থক্য? (সহজ)

preventDefault ব্রাউজারের নিজস্ব আচরণ থামায় (form submit হয়ে পাতা reload, link-এ যাওয়া); event ওঠা-নামা চলতে থাকে। stopPropagation event-কে পরের element-এ যেতে দেয় না; ডিফল্ট আচরণ ঘটে। পর্ব ৩৮

ভ-২২<script defer> আর <script async>-এর পার্থক্য? (মাঝারি)

দুটিই HTML parse না থামিয়ে নামায়। defer চলে parse শেষে, লেখার ক্রমে — নিজের অ্যাপের script-এর জন্য। async নামা শেষ হলেই চলে, ক্রমের নিশ্চয়তা নেই — analytics-এর মতো স্বাধীন script-এর জন্য। type="module" ডিফল্টে defer-এর মতো। পর্ব ০২

ভ-২৩origin কী? http://shop.example আর https://shop.example কি একই origin? (সহজ)

origin = scheme + host + port. scheme আলাদা (http বনাম https), তাই আলাদা origin — port-ও আলাদা (80 বনাম 443). api.shop.example-ও আলাদা origin. পর্ব ৪৩

পেশাদার JavaScript ও প্রজেক্ট (পর্ব ৪৫–৫৫)

ভ-২৪npm install আর npm ci-এর পার্থক্য? (সহজ)

npm install range মেনে প্যাকেজ বসায় আর দরকার হলে lockfile হালনাগাদ করে। npm ci lockfile হুবহু মেনে পরিষ্কার করে বসায়, lockfile আর package.json না মিললে ব্যর্থ হয় — CI আর deploy-এর জন্য। পর্ব ৪৬

ভ-২৫API key বা database password কোথায় রাখবেন? (সহজ)

কোডে নয় — environment variable-এ (process.env), লোকালে .env ফাইলে যা .gitignore-এ থাকে, আর সার্ভারে host-এর secret ব্যবস্থায়। front-end bundle-এ রাখা কোনো কিছু গোপন নয় — যে কেউ পড়তে পারে। পর্ব ৪৯, পর্ব ৫৫

ভ-২৬Node-এ বড় ফাইলের জন্য stream কেন? (মাঝারি)

readFile পুরো ফাইল একবারে মেমরিতে তোলে — ২ GB লগে মেমরি ফুরিয়ে যেতে পারে। stream ছোট ছোট chunk-এ পড়ে-লেখে, মেমরি প্রায় স্থির থাকে; pipeline backpressure সামলায় আর error হলে সব বন্ধ করে। পর্ব ৪৯

ভ-২৭ব্যবহারকারীর password ডেটাবেসে কীভাবে রাখবেন? (মাঝারি)

কখনো সরাসরি বা উল্টানো যায় এমন এনক্রিপশনে নয় — bcrypt বা argon2-এর মতো ধীর, salt-যুক্ত password hashing-এ। লগইনে আবার hash করে মেলানো হয়। SHA-256 একা যথেষ্ট নয় — খুব দ্রুত, তাই অনুমান করে ভাঙা সহজ। পর্ব ৫০

ভ-২৮ফলো-আপ: JWT-র payload কি গোপন? (মাঝারি)

না — payload শুধু base64url-এ লেখা, যে কেউ পড়তে পারে; স্বাক্ষর শুধু নিশ্চিত করে যে কেউ বদলায়নি। তাই JWT-তে password বা ব্যক্তিগত তথ্য রাখবেন না, আর মেয়াদ (exp) ছোট রাখুন। পর্ব ৫০, পর্ব ৪০

যে ফলো-আপ প্রায় নিশ্চিত আসে

প্রথম প্রশ্নসম্ভাব্য ফলো-আপকোথায় প্রস্তুতি
closure কী?লুপে var বনাম let? closure কি memory leak ঘটাতে পারে? React-এর stale closure কী?অংশ ২, গ-০১
== বনাম ===?[] == ![] কেন true? NaN কীভাবে চিনবেন?ক-০৪, ভ-০৪
this কী?arrow-এ this? setTimeout-এ method পাঠালে কী হয়? bind দুবার করলে?গ-০৩, গ-০৪
event loop?then বনাম setTimeout? async-এর await-এর আগের অংশ? Node-এর nextTick?ঘ-০১, অংশ ৯-এর ডায়াগ্রাম
Promise.all?একটি ব্যর্থ হলে বাকিগুলো কি থামে? polyfill লিখুন। allSettled কখন?ঘ-০৩, ঘ-০৪
CORS?preflight কখন? CORS কি সার্ভারকে রক্ষা করে? cookie পাঠাতে কী লাগে?ঙ-০৬
localStorage?token কোথায় রাখবেন? XSS হলে কী হয়?ঙ-০৩, ঙ-০৫
middleware?ক্রম কেন জরুরি? async error কীভাবে ধরবেন?চ-০৭

১০ · AI-কে ভাইভা পরীক্ষক বানান — আর তাকে যাচাই করুন

ভাইভা অনুশীলনের সবচেয়ে বড় সমস্যা হলো প্রশ্ন করার মানুষ না থাকা। AI এখানে কাজের সঙ্গী — ক্লান্ত হয় না, যেকোনো সময় প্রস্তুত, আর আপনার উত্তর থেকে follow-up প্রশ্ন বানাতে পারে। কিন্তু নিজে থেকে AI প্রায়ই খুব নরম পরীক্ষক — সব উত্তরেই প্রশংসা করে। আর JavaScript-এর সূক্ষ্ম আচরণে (microtask-এর ক্রম, coercion, this) বা সংস্করণভিত্তিক তথ্যে (কোন সুবিধা কোন ES সংস্করণে, Node-এর কোন সংস্করণে) AI-ও আত্মবিশ্বাসের সাথে ভুল বলতে পারে। তাই তাকে স্পষ্ট নিয়ম দিন, আর প্রতিটি দাবি যাচাই করুন।

নিচের prompt-টি কপি করে যেকোনো AI চ্যাটে দিন। বিষয়ের জায়গায় যে মডিউল ঝালাতে চান সেটি লিখুন:

তুমি একজন কড়া JavaScript ভাইভা পরীক্ষক। বিষয়: [Asynchronous JavaScript — event loop, Promise, async/await]. ধরে নাও আধুনিক ব্রাউজার আর Node.js 20. নিয়ম: ১. একবারে একটিই প্রশ্ন করো, তারপর আমার উত্তরের জন্য অপেক্ষা করো। ২. আমার উত্তর থেকেই একটু গভীর একটি follow-up প্রশ্ন বানাও, যেমন সত্যিকারের ভাইভা বোর্ড করে। ৩. প্রতিটি উত্তরকে ১০-এর মধ্যে নম্বর দাও, আর ঠিক কোন তথ্য ভুল বা বাদ পড়েছে বলো। প্রশংসা নয়, সঠিকতা। ৪. আমি ভুল বললে সাথে সাথে সঠিক উত্তর দিও না; আগে একটা ইঙ্গিত দিয়ে আরেকবার চেষ্টা করতে দাও। ৫. আমার উত্তর "সংজ্ঞা, উদাহরণ, সুবিধা বা সীমা" কাঠামো মেনেছে কি না বলো। ৬. মাঝে মাঝে ছোট কোড দিয়ে আউটপুট জিজ্ঞেস করো, আর আউটপুট ব্রাউজার না Node-এর তা স্পষ্ট বলো। ৭. কোনো তথ্যে তুমি নিশ্চিত না হলে স্পষ্ট বলো; কোন ES বা Node সংস্করণে কী এসেছে তা আন্দাজে বলো না। ৮. ১০টি প্রশ্নের পর আমার দুর্বল জায়গার তালিকা দাও, আর কোন ধারণা আবার পড়া উচিত বলো।

লিখিত উত্তরের জন্য খাতার উত্তর টাইপ করে দিন এবং বলুন: “এটি একটি ৫ নম্বরের ‘উদাহরণসহ লিখুন’ প্রশ্নের উত্তর। পরীক্ষক হিসেবে নম্বর দাও, আর সংজ্ঞা, উদাহরণ, ব্যাখ্যা, সুবিধা-সীমা — কোন অংশ দুর্বল বলো; কিন্তু পুরো উত্তর নতুন করে লিখে দিও না।” শেষ শর্তটি জরুরি — নইলে আপনি শিখবেন না, শুধু আরেকটি উত্তর মুখস্থ করবেন। নিজের প্রজেক্ট নিয়েও একই কাজ করুন: README দিয়ে বলুন “এই প্রজেক্ট নিয়ে আমাকে পাঁচটি কঠিন ভাইভা প্রশ্ন করো” — তবে .env, API key বা আসল গ্রাহকের তথ্য আগে সরিয়ে নিন।

JavaScript নিয়ে AI-এর উত্তরে যেসব ভুল প্রায়ই থাকে

AI যা বলে বা লেখেআসল সত্য
“object pass-by-reference হয়”pass-by-sharing — reference-এর কপি যায়; parameter-এ নতুন object দিলে বাইরে বদলায় না (খ-০১)
setTimeout(fn, 0) আর then-এর ক্রম উল্টো বলাmicrotask আগে, task পরে — কোড চালিয়ে দেখুন (ঘ-০১)
“fetch 404-এ reject করে” আর res.ok পরীক্ষা বাদশুধু নেটওয়ার্ক ব্যর্থতা বা abort-এ reject (ঘ-০৬)
Node 20-এর জন্য লেখা কোডে Object.groupBy বা নতুন APINode 21 থেকে; লক্ষ্য পরিবেশের সংস্করণ মিলিয়ে নিন (খ-০৫)
“CORS error client-এ mode: 'no-cors' দিয়ে সারান”তাতে উত্তর পড়াই যায় না; সার্ভারের header ঠিক করুন (ঙ-০৬)
login token localStorage-এ রাখা, ইনপুট innerHTML-এ বসানোXSS-এ চুরি যায়; HttpOnly cookie, textContent (ঙ-০৩, ঙ-০৫)
অস্তিত্বহীন বা কাছাকাছি নামের npm প্যাকেজ প্রস্তাবnpm registry-তে নাম, প্রকাশক আর ডাউনলোড যাচাই করুন — নকল নামের প্যাকেজ সরবরাহ-শৃঙ্খলের আক্রমণে ব্যবহার হয়

AI-এর উত্তর যাচাইয়ের চেকলিস্ট

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

এগুলো মুখস্থের প্রশ্ন নয় — পরীক্ষা আর শেখা নিয়ে একটু থেমে ভাবার প্রশ্ন। নিজে কিছুক্ষণ ভাবুন, তারপর প্রশ্নে চেপে উত্তর দেখুন।

প্র ০১JavaScript-এর পরীক্ষায় coercion আর typeof null-এর মতো “অদ্ভুত” আচরণ নিয়ে এত প্রশ্ন আসে কেন? এগুলো কি শুধু ফাঁদ?

ইতিহাস দিয়ে শুরু করা যাক। ১৯৯৫ সালের মে মাসে Netscape-এ Brendan Eich খুব অল্প সময়ে — প্রচলিত বর্ণনায় প্রায় দশ দিনে — ভাষাটির প্রথম রূপ বানান; নাম ছিল Mocha, তারপর LiveScript, আর সেই বছরের শেষে JavaScript. লক্ষ্য ছিল ওয়েব ডিজাইনারদের জন্য ক্ষমাশীল একটি ভাষা: ভুল টাইপ দিলেও যেন পাতা ভেঙে না যায়। তাই == নিজে থেকে রূপান্তর করে, ভুল জায়গায় মান দিলে চুপচাপ global variable তৈরি হয়।

এরপর আসে ওয়েবের সবচেয়ে বড় নিয়ম — “don't break the web”. একবার কোটি পাতা কোনো আচরণের ওপর নির্ভর করলে তা আর বদলানো যায় না। typeof null === 'object' ঠিক করার প্রস্তাব এসেছিল, কিন্তু পুরোনো কোড ভাঙবে বলে গৃহীত হয়নি। ভাষা তাই পুরোনো আচরণ না সরিয়ে নতুন, নিরাপদ পথ যোগ করেছে: ===, strict mode, let/const, Number.isNaN, Object.is, ??.

তাহলে এই প্রশ্নগুলো কি শুধু ফাঁদ? আসলে এগুলো দুটি জিনিস যাচাই করে। প্রথমত, আপনি নিয়মটি জানেন কি না — ==-এর রূপান্তর, falsy মানের তালিকা। দ্বিতীয়ত, আরও গুরুত্বপূর্ণ — আপনি জানেন কি না এগুলো এড়াতে হয়। সেরা উত্তর তাই দুই অংশের: “[] == ![] true, কারণ … ; আর এ কারণেই আমি সবসময় === লিখি, ESLint-এর eqeqeq চালু রাখি।”

মূল উপলব্ধি: অদ্ভুত আচরণের প্রশ্ন আসলে ভাষার ইতিহাস আর নিরাপদ অভ্যাসের প্রশ্ন। নিয়ম বলুন, তারপর বলুন কীভাবে এড়ান।

প্র ০২React বা Express জানা কি যথেষ্ট? ইন্টারভিউতে core JavaScript নিয়ে এত প্রশ্ন কেন?

JavaScript-এর framework-এর ইতিহাস দ্রুত বদলের ইতিহাস। ২০০৬ সালে jQuery এলো, প্রায় এক দশক সে ছিল ওয়েবের মানদণ্ড। ২০১০ সালে AngularJS, ২০১৩ সালে React, ২০১৪ সালে Vue, ২০১৬ সালে Svelte — আর AngularJS-এর পরের Angular প্রায় নতুন একটি framework. যে ডেভেলপার শুধু একটি framework-এর API মুখস্থ করেছেন, তাঁর জ্ঞানের মেয়াদ সেই framework-এর জনপ্রিয়তার সমান।

কিন্তু সব framework-এর নিচে একই ভাষা। React-এর stale closure বুঝতে closure লাগে; useEffect-এর cleanup বুঝতে memory leak আর event listener; state বদলানোর নিয়ম বুঝতে reference আর immutable update; Express-এর error middleware বুঝতে async error আর Promise. framework-এর অনেক “রহস্যময়” বাগ আসলে core JavaScript-এর বাগ।

পরীক্ষকেরা তাই core প্রশ্ন করেন — এগুলো দেখায় আপনি নতুন framework কত দ্রুত ধরতে পারবেন, আর কোনো বাগে আটকে গেলে মূল কারণ পর্যন্ত যেতে পারবেন কি না। তার মানে এই নয় যে framework অপ্রয়োজনীয়: বাস্তব কাজে প্রায় সবসময় একটি লাগে, আর পোর্টফোলিওতে একটি framework-এ বানানো প্রজেক্ট আপনার প্রস্তুতির প্রমাণ।

মূল উপলব্ধি: framework হলো আজকের হাতিয়ার, ভাষা হলো ভিত্তি। ভাইভায় framework-এর প্রশ্নের উত্তরও core ধারণা দিয়ে ব্যাখ্যা করতে পারলে উত্তর সবচেয়ে শক্ত হয়।

প্র ০৩মডেল উত্তর মুখস্থ করলে সমস্যা কী? নিজের ভাষায় বলতে পারা কেন এত গুরুত্বপূর্ণ?

মুখস্থ উত্তরের সমস্যা ধরা পড়ে প্রথম ফলো-আপেই। ধরা যাক আপনি “closure কী”-এর সংজ্ঞা হুবহু মনে রেখেছেন। পরীক্ষক জিজ্ঞেস করলেন: “তাহলে প্রতিটি function-ই কি closure?” সংজ্ঞায় এর উত্তর নেই। যিনি বুঝেছেন, তিনি যুক্তি দিয়ে বলবেন: “হ্যাঁ, JavaScript-এ প্রতিটি function তার জন্মস্থানের environment ধরে রাখে; আমরা সাধারণত closure বলি তখন, যখন বাইরের function শেষ হওয়ার পরেও ভেতরের function সেই variable ব্যবহার করে।”

পদার্থবিজ্ঞানী Richard Feynman-এর নামে একটি শেখার পদ্ধতি প্রচলিত — “Feynman technique”: একটি ধারণা এমনভাবে ব্যাখ্যা করার চেষ্টা করুন যেন একজন নতুন শিক্ষার্থীকে বোঝাচ্ছেন; যেখানে আটকে যান বা কঠিন শব্দের আড়ালে লুকাতে হয়, সেখানেই বোঝায় ফাঁক। পদ্ধতিটি তিনি নিজে এই নামে লেখেননি, কিন্তু সহজ ভাষায় ব্যাখ্যার প্রতি তাঁর জোর সুপরিচিত।

JavaScript-এ এর একটি বাড়তি সুবিধা আছে: প্রায় সব দাবি দুই লাইনের কোডে যাচাই করা যায়। এই পাতার প্রোগ্রামগুলো চালানোর আগে আউটপুট আন্দাজ করুন, তারপর একটি লাইন বদলে আবার আন্দাজ করুন — let-কে var করুন, results[i]-কে push করুন। যেখানে আন্দাজ ভুল হয়, সেখানেই আপনার শেখার জায়গা।

মূল উপলব্ধি: মডেল উত্তর হলো কাঠামো ও মানের নমুনা, মুখস্থের জিনিস নয়। আপনার লক্ষ্য একই তথ্য নিজের ভাষায়, নিজের উদাহরণে বলতে পারা।

প্র ০৪“জানি না” বলা কেন অনেক সময় আন্দাজে উত্তর দেওয়ার চেয়ে ভালো? আত্মবিশ্বাস আর জ্ঞানের সম্পর্ক কী?

১৯৯৯ সালে মনোবিজ্ঞানী Justin Kruger আর David Dunning একটি গবেষণা প্রকাশ করেন, যা পরে “Dunning–Kruger effect” নামে পরিচিত হয়। তাঁদের পরীক্ষায় দেখা যায়, কোনো বিষয়ে সবচেয়ে কম দক্ষ অংশগ্রহণকারীরা প্রায়ই নিজের দক্ষতাকে অনেক বেশি মনে করেছেন — কারণ ভুল চেনার জন্যও কিছু জ্ঞান লাগে। ফলাফলের ব্যাখ্যা ও মাত্রা নিয়ে পরে বিতর্কও হয়েছে, তবে মূল শিক্ষাটি ভাইভায় খুব প্রাসঙ্গিক: আত্মবিশ্বাস আর জ্ঞান এক জিনিস নয়।

পরীক্ষকেরা এটা জানেন। একজন প্রার্থী জোর দিয়ে ভুল বললে — ধরা যাক “fetch 404-এ reject করে” — পরীক্ষক শুধু ওই প্রশ্নের নম্বর কাটেন না; বাকি সব উত্তর নিয়েও সন্দিহান হন। অন্যদিকে “এটা নিশ্চিত জানি না, তবে এভাবে ভাবছি… আর নিশ্চিত হতে console-এ পরীক্ষা করতাম” বলা প্রার্থী দেখান যে তিনি নিজের জ্ঞানের সীমা জানেন আর যাচাইয়ের পথও জানেন।

সফটওয়্যার কাজে এই গুণ আরও জরুরি। কেউ আন্দাজে “এটা নিরাপদ” বলে কোড merge করলে ক্ষতি হয় গ্রাহকের — হয়তো দুবার অর্ডার হয়, বা bKash-এ দুবার টাকা কাটে। যে ডেভেলপার বলেন “নিশ্চিত নই, একটি টেস্ট লিখে দেখি”, দল তাঁর ওপর বেশি ভরসা করে। কিন্তু সীমা আছে: সব প্রশ্নেই “জানি না” বললে প্রস্তুতির অভাব বোঝায়। সবচেয়ে ভালো পথ মাঝখানে — যা জানেন তা বলা, অনুমানকে অনুমান বলা, আর একেবারে না জানলে সৎভাবে স্বীকার করা।

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

প্র ০৫AI যখন সেকেন্ডে debounce বা deep clone লিখে দেয়, তখন খাতায় বা বোর্ডে এগুলো লিখতে বলা কি অর্থহীন?

প্রশ্নটি ন্যায্য, আর উত্তর হলো — লক্ষ্য বদলেছে, প্রয়োজন ফুরায়নি। “একটি debounce লিখুন” প্রশ্নে পরীক্ষক আসলে সাত লাইনের কোড চান না; তিনি দেখতে চান আপনি closure (timer কোথায় বাঁচে), timer বাতিল, this আর আর্গুমেন্ট হারানোর ফাঁদ বোঝেন কি না। Promise.all-এর polyfill দেখায় আপনি “ক্রম রাখা” আর “প্রথম ব্যর্থতায় reject”-এর মতো চুক্তি সঠিকভাবে ধরতে পারেন কি না।

AI-এর যুগে এই দক্ষতা আরও দামি, কারণ এখন আপনার কাজের বড় অংশ হবে অন্যের — মানুষের বা AI-এর — লেখা কোড পড়া ও যাচাই করা। AI-এর লেখা debounce যদি this হারায়, বা deepClone যদি circular reference-এ অসীম recursion-এ পড়ে, তা ধরতে পারবেন শুধু তিনিই, যিনি নিজে একবার লিখে ভুলগুলো দেখেছেন। রিভিউ করার ক্ষমতা লেখার ক্ষমতার ওপর দাঁড়িয়ে থাকে।

বাস্তবে তাই সেরা প্রস্তুতি দুই ধাপের: আগে নিজে লিখুন — খাতায় বা editor-এ, AI ছাড়া — আর চালিয়ে দেখুন। তারপর AI-কে একই সমস্যা দিন, আর দুটি সমাধান তুলনা করুন: কোনটি কোন edge case সামলায়, কোনটি সহজ, কোনটিতে বাগ। এই তুলনাটিই ইন্টারভিউতে বলার মতো একটি ভালো গল্প।

মূল উপলব্ধি: হাতে লেখার প্রশ্ন এখন বোঝা আর যাচাই করার ক্ষমতার পরীক্ষা। নিজে লিখতে পারলে তবেই AI-এর লেখা নিরাপদে ব্যবহার করতে পারবেন।

নিজেকে যাচাই করুন — উত্তর লেখার কৌশল ও JavaScript-এর মূল তথ্য

প্রথমে একটি ক্রম সাজানোর প্রশ্ন, তারপর উত্তর লেখার কৌশল আর JavaScript-এর ক্লাসিক ভাইভা তথ্য নিয়ে MCQ. ভুল হলে কারণসহ ব্যাখ্যা পাবেন।

ক্রম“X কী? উদাহরণসহ ব্যাখ্যা করুন” প্রশ্নের একটি ভালো উত্তরের অংশগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. 📌 এক–দুই বাক্যের নির্ভুল সংজ্ঞা
  2. 💻 ছোট কোড উদাহরণ, নিচে আউটপুট
  3. 🗺️ ভেতরে কীভাবে কাজ করে — ছোট চিত্রসহ
  4. ⚖️ সুবিধা, সীমা আর সাধারণ ফাঁদ
  5. ✅ উপসংহার — কখন ব্যবহার করবেন

“closure কী? উদাহরণসহ লিখুন” — একটি ৫ নম্বরের প্রশ্নে কোন উত্তরটি পূর্ণ নম্বরের সবচেয়ে কাছে?

  • ব্যাখ্যা ছাড়া তিনটি বড় প্রোগ্রাম
  • দুই বাক্যের সংজ্ঞা, আউটপুটসহ counter উদাহরণ, scope chain-এর ছোট চিত্র, ব্যবহার ও memory-র সীমা, এক লাইনের উপসংহার
  • “function-এর ভেতরে function হলো closure” — এক লাইন
  • দুই পাতা জুড়ে JavaScript-এর ইতিহাস, শেষে closure-এর নাম

ভাইভায় এমন প্রশ্ন এলো, যার উত্তর আপনি পুরোপুরি জানেন না। সবচেয়ে ভালো পদক্ষেপ কোনটি?

  • আত্মবিশ্বাস দেখাতে আন্দাজে একটি উত্তর জোর দিয়ে বলা
  • চুপ করে থাকা, যতক্ষণ না পরের প্রশ্ন আসে
  • “পুরো নিশ্চিত নই, তবে এভাবে ভাবছি…” বলে যা জানেন তা থেকে যুক্তি দেওয়া, আর কীভাবে যাচাই করতেন তা বলা
  • প্রশ্ন এড়িয়ে নিজের জানা অন্য বিষয়ে কথা বলা শুরু করা

JavaScript-এ null == undefined আর null === undefined-এর মান যথাক্রমে কী?

  • true আর false
  • true আর true
  • false আর false
  • TypeError

কয়েকটি API call-এর মধ্যে কিছু ব্যর্থ হতে পারে, কিন্তু আপনি সবগুলোর ফল (সফল বা ব্যর্থ) একসাথে চান, আর ফলের Promise কখনো reject হবে না। কোনটি ব্যবহার করবেন?

  • Promise.all
  • Promise.race
  • Promise.any
  • Promise.allSettled

একটি script-এ পরপর setTimeout(() => log('T'), 0) আর Promise.resolve().then(() => log('P')) লেখা, শেষে log('S'). আউটপুটের ক্রম কী?

  • T, P, S
  • S, P, T
  • S, T, P
  • P, T, S

ব্রাউজারে ডেটা রাখার কোন উপায়টি মিল থাকা প্রতিটি HTTP request-এর সাথে নিজে থেকে সার্ভারে যায়?

  • localStorage
  • sessionStorage
  • cookie
  • IndexedDB

ব্রাউজারে অন্য origin-এর API-তে কোন fetch request-এর আগে ব্রাউজার একটি CORS preflight (OPTIONS) পাঠাবে?

  • POST, header Content-Type: application/json
  • কোনো বাড়তি header ছাড়া সাধারণ GET
  • POST, Content-Type: application/x-www-form-urlencoded
  • বাড়তি header ছাড়া HEAD

একটি search box-এ প্রতিটি অক্ষর টাইপের সাথে API call যাচ্ছে। ব্যবহারকারী টাইপ থামানোর ৩০০ ms পরে মাত্র একবার call পাঠাতে কোন কৌশল সবচেয়ে উপযুক্ত?

  • throttle
  • polling
  • memoization
  • debounce

Express-এ একটি middleware next(err) ডাকলে কী ঘটে?

  • পরের সাধারণ middleware স্বাভাবিকভাবে চলে, error উপেক্ষিত হয়
  • বাকি সাধারণ middleware বাদ দিয়ে (err, req, res, next) আকারের error middleware-এ যায়
  • Node.js process সাথে সাথে বন্ধ হয়ে যায়
  • Express request-টি আবার শুরু থেকে চালায়

শব্দকোষ

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

মনে রাখুন

  1. বড় প্রশ্নে পাঁচ অংশ: সংজ্ঞা → উদাহরণ (কোড + আউটপুট) → কীভাবে কাজ করে → সুবিধা ও সীমা → উপসংহার; “পার্থক্য লিখুন” প্রশ্নে দুটির সংজ্ঞা আর একই মাপকাঠির টেবিল।
  2. “function লিখুন” প্রশ্নে আগে চুক্তি, তারপর কোড; wrapper-এ ...args আর fn.apply(this, args); নিচে আউটপুট, edge case আর জটিলতা।
  3. যে আউটপুট পরিবেশের ওপর নির্ভর করে, সেখানে অনুমান স্পষ্ট করুন: ব্রাউজার বনাম Node, strict বনাম sloppy, কোন ES ও Node সংস্করণ।
  4. ভাইভায় তিন বাক্য — সংজ্ঞা, উদাহরণ, সীমা; না জানলে সৎভাবে যুক্তি দিয়ে এগোন আর যাচাইয়ের উপায় বলুন; নিজের প্রজেক্টের প্রতিটি সিদ্ধান্তের কারণ নিজের ভাষায় বলতে পারুন।
  5. AI দিয়ে ভাইভা অনুশীলন করুন, কিন্তু তার প্রতিটি কোড চালিয়ে আর প্রতিটি সংস্করণ-দাবি মিলিয়ে নিন।

পরের পর্বে: কোর্সের শেষ পর্ব — JavaScript কোডিং ইন্টারভিউ। অচেনা সমস্যা থেকে প্রশ্ন করে শর্ত বোঝা, সরল সমাধান থেকে ভালো সমাধানে যাওয়া, আর ইন্টারভিউয়ারের সামনে জোরে ভেবে পরিষ্কার JavaScript লেখা।

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

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