Reactive Accelerator
Javascript Refresher

Setting Up JavaScript - "JavaScript" in html file

Where to put <script> tag in html head/`body

HTML এর মধ্যে JavaScript চালানোর জন্য <script> ট্যাগ ব্যবহার করা হয়। JavaScript কোড আমরা লিখতে পারি দুইভাবে:

  1. Inline JavaScript (HTML ফাইলের ভেতরেই কোড)
  2. External JavaScript (আলাদা .js ফাইলে রেখে src দিয়ে লিঙ্ক করা)

Script Tag কোথায় বসাবো?

Option 1: <head> এর ভেতরে

<!DOCTYPE html>
<html>
    <head>
        <script src="script.js"></script>
    </head>
    <body>
        <h1>Hello World</h1>
    </body>
</html>

সমস্যা কী?

  • যখন browser HTML পড়ে <script> দেখে, তখন সেটা লোড এবং চালানো শুরু করে।
  • JS ফাইল লোড হওয়া পর্যন্ত HTML parsing বন্ধ থাকে। এটাকে বলা হয় Render Blocking।
  • যদি JS DOM-এ কিছু access করতে চায় (যেমন document.getElementById) — তখন সেটা কাজ করবে না কারণ HTML এখনো পুরো লোড হয়নি।

ব্যবহার করবেন না যদি DOM access করতে হয়!

Option 2: <body> এর শেষে (before </body>)

<!DOCTYPE html>
<html>
    <head>
        <title>My Page</title>
    </head>
    <body>
        <h1>Hello World</h1>
        <script src="script.js"></script>
    </body>
</html>

এটা সবচেয়ে জনপ্রিয় ও সহজ উপায়

  • HTML আগে parse হয়, তারপর JS চলে
  • DOM পুরো available থাকে
  • JS সব element access করতে পারে
  • No render blocking → faster page load

async vs defer: কী কাজ করে কীভাবে?

<script> ট্যাগে async বা defer attribute দিলে, JavaScript execution control করা যায়।

async

<script src="script.js" async></script>

কিভাবে কাজ করে?

  • Script HTML এর সাথে সাথে লোড হয় (non-blocking)
  • কিন্তু লোড হতেই সাথে সাথে execute হয়
  • DOM এখনও পুরো load না হলেও JS চলে যেতে পারে

সমস্যাঃ

  • যদি DOM element access করে, তখন error আসতে পারে
  • multiple async script থাকলে execution order এলোমেলো হতে পারে

defer

<script src="script.js" defer></script>

কিভাবে কাজ করে?

  • HTML parse করার সময়েই script লোড হয় (non-blocking)
  • কিন্তু execute করে DOM parse শেষ হওয়ার পরেই
  • multiple defer script থাকলে যে order এ লেখা হয়েছে, সেই order এ চলে

Best practice:

  • নিজের JavaScript file → defer ব্যবহার করো
  • DOM access করতে হলে defer always safe

তুলনামূলক টেবিল: async vs defer

Featureasyncdefer
Load behaviorHTML parse এর সাথে সাথে লোড হয়HTML parse এর সাথে সাথে লোড হয়
Execute behaviorLoad হওয়া মাত্র execute হয়DOM parse শেষ হলে execute হয়
Execution Orderযেভাবেই লোড হয়, সেইভাবে চলেHTML এ যেভাবে লেখা, সেইভাবে চলে
DOM ready timeDOM এর আগে execute হতে পারেDOM parse শেষ হওয়ার পর চলে
Use CaseThird-party script, ads, trackingPage এর নিজস্ব scripts

Visual Diagram: Execution Flow

No attribute:
HTML -----[BLOCK]-- JS --[RESUME]--> DOM

async:
HTML -----⟶⟶ [JS loaded & executed immediately] ⟶⟶ DOM continues

defer:
HTML ⟶⟶ [JS loaded in background] ⟶⟶ DOM parsed completely ⟶⟶ [JS executed in order]

কখন কী ব্যবহার করবো?

ScenarioSuggested Script Setup
Simple demo/test project<script> at end of <body>
DOM access needed before running scriptdefer (in <head>)
Tracking or analytics script (e.g., Google)async
Multiple dependent JS filesdefer maintains order
Using modern frameworks like React/VueUsually handled via build tools (Webpack)

Bonus: Inline Script + DOM Ready

যদি inline JS লেখো এবং <head> এ রাখতে চাও, তাহলে DOM ready হবার event শুনতে হবে:

<script>
    document.addEventListener("DOMContentLoaded", function () {
        // All DOM elements are ready
        const heading = document.querySelector("h1");
        heading.textContent = "Hello from JS!";
    });
</script>

Best Practices Summary

  • Use <script src="app.js" defer></script> inside <head> → most modern and safe
  • Or, use <script> just before closing </body> tag
  • Avoid placing blocking <script> inside <head> unless absolutely necessary
  • Use async only for third-party independent scripts

Final Example: Best Setup for Beginners

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Best JS Setup</title>
        <script src="main.js" defer></script>
    </head>
    <body>
        <h1>Welcome to JavaScript</h1>
    </body>
</html>
// main.js
document.addEventListener("DOMContentLoaded", () => {
    const h1 = document.querySelector("h1");
    h1.textContent = "JavaScript is Working!";
});

where to put script

অর্থাৎ html এর head এর ভিতর defar attribute দিয়ে script লোড করা সবচাইতে ভালো। এটা DOM এর জন্য সেফ এবং render blocking হয়না।


Scope in JavaScript

Primitive and Reference types Value

Primitive

প্রিমিটিভ এর বাংলা অর্থ হলো আদিম। জাভাস্ক্রিপ্টে যেসব DATATYPE আছে যেমনঃ

  • String
  • Number
  • BigInt
  • Boolean
  • Null
  • Undefined
  • Symbol

এইগুলো হলো জাভাস্ক্রিপ্টের মূল বা একক। এগুলো ব্যাবহার করে অন্যান্য ডাটা বানানো হয়। এগুলোকে বলা হয় প্রিমিটিভ ডাটা বা ভ্যালু ।

References

জাভাস্ক্রিপ্টের Array এবং Object কে বলা হয় রেফারেন্স টাইপ ডাটা বা ভ্যালু ।

প্রিমিটিভ এবং রেফারেন্স টাইপ ডাটার পার্থক্যঃ

প্রিমিটিভ এবং রেফারেন্স টাইপ ডাটার মধ্যে মূল যেই পার্থক্য রয়েছে তা হলো এর ডাটার বিহেবিয়ার নিয়ে। যেমন নিচে উদাহরণের মাধ্যমে বুঝানো হলোঃ

Primitive

Primitive

প্রিমিটিভ ডাটা শুধুমাত্র ভ্যালুটা শেয়ার করে। ডাটার রেফারেন্স শেয়ার করেনা।

Reference

Reference

এখানে a কে যখন b দ্বারা রি-এসাইন করা হয়েছে তখন স্বাভাবিক ভাবেই আ এর ভ্যালু চেঞ্জ হয়ে b এর যেই ভ্যালু ছিল তা হয়ে গিয়েছে। কিন্তু নিচে যখন b এর ভ্যালু চেঞ্জ করা হয়েছে সেই চেঞ্জটা a তেও এসে প্রভাব ফেলেছে এবং a সহ চেঞ্জ হয়ে গেছে। কারণ এখানে a তে যখন b এসাইন করা হয়েছিল তখন a তে b এর রেফারেন্স সহ চলে গেছিল,তাই যেকোন একটা কে চেঞ্জ করলেই দুইটাই চেঞ্জ হয়ে যাচ্ছে।

এখানে যেই বিষয়টা হয়েছে তা হলোঃ

Reference

a আর b যখন ডিফাইন করা হয়েছে তখন মেমরিতে দুইটা Array এলোকেটেড করা হয়েছে এবং Array দুটি তাদের যেই Variables এর নাম a এবং b তার দিয়ে পয়েন্ট করে আছে। কিন্তু যখন a = b করা হয়েছে তখন দুইটা পয়েন্টার এক হয়ে b এর ভ্যালু থেকে a আর b এর দিকে পয়েন্ট হয়ে গেছে। তাই এখন a অথবা b যেইটাই চেঞ্জ করা হউক না কেন তা দুইটাকেই চেঞ্জ করবে।

এটাই হলো primitives আর References ভ্যালুর মধ্যে মূল পার্থক্য । তাছাড়াও আরো কিছু পার্থক্য রয়েছে তার ভিতরে এর স্টোরেজ লোকেশন এবং মেমরি এলোকেশন অন্যতম।

Memory Allocation

দুই ধরনের মেমোরিতে জাভাস্ক্রিপ্টের ডাটা স্টোর হয়। ১। Stack Memory ২। Heap Memory Stack Memory হলো প্রিমিটিভ ডাটার জন্য এবং Heap Memory হলো রেফারেন্স টাইপ ডাটার জন্য। Heap Memoryএলোকেটেড হয় ডাইনামিক্যালি। অর্থাৎ যখনই প্রয়োজন হয় তখনই মেমোরি এলোকেটেড হয় এবং যখন প্রয়োজন শেষ হয়ে যায় তখন মেমোরি ফ্রি করে দেয়া হয়। সেজন্য Heap Memory প্রতিটা মেমরি এলোকেশনের সময় একটা ইউনিক এইডেন্টিফায়ার ব্যাবহার হয়। যাতে সেই আইডেন্টিফায়ার দিয়ে সেই মেমরিকে ট্র্যাক করা যায়। কিন্তু Stack Memory হলো স্ট্যাটিক। অর্থাৎ যখনই প্রোগ্রাম রান হবে তখনই মেমোরি এলোকেটেড হবে এবং প্রোগ্রাম শেষ হলে মেমোরি ফ্রি হয়ে যাবে।

Shallow Copy Vs Deep Copy

জাভাস্ক্রিপ্টে "শ্যালো কপি" (Shallow Copy) এবং "ডিপ কপি" (Deep Copy) হল দুটি আলাদা প্রক্রিয়া যেগুলো ব্যবহার করে একটি Object বা Array'র কপি তৈরি করা হয়। তবে এদের মধ্যে বড় পার্থক্য হচ্ছে কিভাবে ডেটা কপি করা হয়। নিচে প্রতিটি কনসেপ্ট বিস্তারিতভাবে ব্যাখ্যা করছি:

শ্যালো কপি (Shallow Copy)

শ্যালো কপিতে কেবলমাত্র অবজেক্টের প্রথম লেভেলের ভ্যালুগুলি কপি করা হয়। এর মানে হলো, যদি অবজেক্ট বা আরে'র মধ্যে নেস্টেড অবজেক্ট থাকে, তাহলে সেগুলি রেফারেন্স হিসেবে কপি হয়। অর্থাৎ, নেস্টেড অবজেক্ট বা আরে'র জন্য একটি রেফারেন্স তৈরি হয়, নতুন অবজেক্টে একই ডেটা শেয়ার করে।

উদাহরণ:

let originalArray = [1, 2, { a: 3, b: 4 }];
 
// শ্যালো কপি তৈরি করা
let shallowCopy = [...originalArray];
 
console.log(shallowCopy); // [1, 2, { a: 3, b: 4 }]
 
// নেস্টেড অবজেক্ট পরিবর্তন করা
shallowCopy[2].a = 10;
 
console.log(originalArray); // [1, 2, { a: 10, b: 4 }]
console.log(shallowCopy); // [1, 2, { a: 10, b: 4 }] // নেস্টেড অবজেক্ট রেফারেন্স একারে কপি হওয়ার কারনে কপি ডাটাতে চেঞ্জ করলেও তা মেইন ডাটাকেও চেঞ্জ করে দিয়েছে।

এই উদাহরণে দেখা যাচ্ছে যে, originalArray এবং shallowCopy একই নেস্টেড অবজেক্ট শেয়ার করছে। যখন shallowCopy[2].a পরিবর্তন করা হয়, তখন মূল অবজেক্টেও পরিবর্তন ঘটে। এটি শ্যালো কপির একটি সীমাবদ্ধতা।

শ্যালো কপি তৈরি করার পদ্ধতি:

  • Spread Operator: let copy = [...array];

ডিপ কপি (Deep Copy)

ডিপ কপিতে একটি অবজেক্টের প্রতিটি লেভেলের কপি তৈরি করা হয়, এমনকি নেস্টেড অবজেক্টেরও আলাদা কপি করা হয়। এর ফলে মূল অবজেক্টের কোনো পরিবর্তন নতুন কপি অবজেক্টকে প্রভাবিত করে না এবং বিপরীতও ঘটে না।

উদাহরণ:

let originalArray = [1, 2, { a: 3, b: 4 }];
 
// ডিপ কপি তৈরি করা (JSON পদ্ধতি ব্যবহার করে)
let deepCopy = JSON.parse(JSON.stringify(originalArray));
 
console.log(deepCopy); // [1, 2, { a: 3, b: 4 }]
 
// নেস্টেড অবজেক্ট পরিবর্তন করা
deepCopy[2].a = 10;
 
console.log(originalArray); // [1, 2, { a: 3, b: 4 }]
console.log(deepCopy); // [1, 2, { a: 10, b: 4 }]

এখানে দেখা যাচ্ছে যে, deepCopy[2].a পরিবর্তন করার পরেও originalArray এর নেস্টেড অবজেক্ট অপরিবর্তিত রয়েছে। কারণ, ডিপ কপিতে নেস্টেড অবজেক্টের নতুন কপি তৈরি হয়।

ডিপ কপি তৈরি করার পদ্ধতি:

    1. JSON.parse(JSON.stringify(obj)): সহজ পদ্ধতি, তবে ফাংশন ও undefined হ্যান্ডেল করতে পারে না।
    1. Lodash লাইব্রেরির cloneDeep মেথড Lodash একটি জনপ্রিয় জাভাস্ক্রিপ্ট লাইব্রেরি, যা অনেক ধরনের ইউটিলিটি ফাংশন সরবরাহ করে। cloneDeep হল একটি বিশেষ মেথড যা ডিপ কপি তৈরি করতে পারে।

উদাহরণ:

প্রথমে lodash ইনস্টল করতে হবে:

 npm i --save lodash

তারপর

const _ = require("lodash");
 
let originalObject = { a: 1, b: { c: 2, d: 3 } };
let deepCopiedObject = _.cloneDeep(originalObject);
 
deepCopiedObject.b.c = 10;
 
console.log(originalObject); // { a: 1, b: { c: 2, d: 3 } }
 
console.log(deepCopiedObject); // { a: 1, b: { c: 10, d: 3 } }

Lodash এর cloneDeep মেথড সমস্ত ডেটা টাইপ এবং নেস্টেড অবজেক্ট সঠিকভাবে হ্যান্ডেল করতে পারে। এটি ফাংশন, তারিখ, Map, Set এবং অন্যান্য জটিল ডেটা স্ট্রাকচার হ্যান্ডেল করার ক্ষেত্রে খুবই কার্যকর।

শ্যালো কপি বনাম ডিপ কপি পার্থক্য:

শ্যালো কপিডিপ কপি
শুধুমাত্র প্রথম লেভেলের কপি করে।প্রতিটি লেভেলের জন্য নতুন কপি তৈরি করে।
নেস্টেড অবজেক্টগুলো রেফারেন্স হিসেবে কপি হয়।নেস্টেড অবজেক্টগুলোর সম্পূর্ণ নতুন কপি হয়।

এই দুই ধরনের কপির মধ্যে পার্থক্য নির্ভর করে আপনার প্রয়োজনের উপর।

Advanced JavaScript

this এর ব্যাবহার। কোথায় এবং কিভাবে ।

Implicit Binding

👉রুলসঃ দেখতে হবে যে,ফাংশন কল হয়েছে কোথায়, যেখানে কল হয়েছে তার সামনে কি কোন ডট আছে কিনা,যদি থাকে তাহলে তার সামনে কি আছে। যদি কিছু থাকে তাহলে সেটাই হলো this । এক্ষেত্রে এক্সেপ্সন হলো this শুধু নরমাল ফাংশনেই কাজ করবে। কিন্তু Arrow ফাংশন this বলে কিছু চিনবেনা।

উদাহরণঃ

let player = {
    name: "Mashrafe",
    age: 38,
    printPlayerName: function () {
        console.log(this.name); // এখানে this দিয়ে `player` অবজেক্টটাকে পয়েন্ট করা হয়েছে।
    },
};
 
player.printPlayerName();

Explicitly Binding

.call()

👉 কখনও কখনও বাহিরের কোন ফাংশনকে অন্য কোন অবজেক্ট দিয়ে কল করার প্রয়োজন হয় । সেক্ষেত্রে সিনট্যাক্স হয় এরকমঃ

function printName() {
    // এটা একটা গ্লোবাল ফাংশন
    console.log(this.name);
}
let player = {
    name: "Sakib",
    age: 33,
};
 
printName.call(player); // এই গ্লোবাল ফাংশনটাকে `player` অবজেক্ট দিয়ে `.call()` করা হয়েছে ।

এক্ষেত্রে .call() এর ভিতরে যা পাস করা হয়, this সেটাকেই পয়েন্ট করে। এক্ষেত্রে explicitly বলে দেয়া হচ্ছে যে this কি হবে ।

.apply()

👉 .apply() আর .call() একই কাজ করে। সবকিছুই সেম। তবে.apply() তার second parameter এ Array নিতে পারে । যেখানে .call() Array নিতে পারেনা।

function printPlayerName() {
    console.log(`${this.name} is ${vertue} `);
}
 
let mashrafe = {
    name: "Mashrafe",
    age: 36,
};
let vartu1 = "Honest";
let vartu2 = "Captain";
let vartu3 = "Leader";
let vertue = [vartu1, vartu2, vartu3];
 
printPlayerName.apply(mashrafe, vertue);

.bind()

👉 .bind().call() এর মতোই সেম কাজ করে। তবে পার্থক্য হলো .bind() ফাংশনটিকে সরাসরি কল না করে দিয়ে ফাংশনের একটা নতুন ইন্সটেন্স রিটার্ন করে। এবং সেই ইন্সটেন্সকে যেই ভেরিয়েবলে রাখা হয় সেই ভেরিয়েবল দ্বারা কল করতে হয়।

উদাহরনঃ

function printAPlayerName() {
    console.log(this.name);
}
 
let bdPlayer = {
    name: "Ashraful",
    age: 39,
};
 
let printFunction = printAPlayerName.bind(bdPlayer);
printFunction();

JS Itarator

Itarables কি ?

Itarables বলতে মূলত সেই সমস্ত জিনিস বা অবজেক্ট কে বোঝায়,যেগুলোর মধ্যে দিয়ে লুপ eg: for...of করে স্টেপ বাই স্টেপ যাওয়া যায়। যেমনঃ Array,String,Map,Set

টেকনিক্যালি বললে, যেসব অবজেক্টের প্রোটোটাইপের ভিতরে symbol.itarator প্রপার্টি রয়েছে সেটাই itarable symbol.itarator এর মাধ্যমেই জাভাস্ক্রিপ্ট ডিফাইন করে যে, কোনটা itarable আর কোনটা নয় ।

💡

Map,Set বলতে এখানে জাভাস্ক্রিপ্ট এর Map Set ডাটা স্ট্রাকচার কে বুঝানো হয়েছে

itarator বলতে কি বুঝায় ?

itarable অবজেক্টকে যার দ্বারা itarate করা যায়,সেটাই হলো itarator

itarating বলতে কি বুঝায় ?

itarating বলতে মূলত Itarables অবজেক্টগুলোকে লুপ করে স্টেপ বাই স্টেপ যাওয়ার যেই প্রসেস সেটাকে বুঝায় । যখন itarate করা হয় তখন সেটা হলো itarating

Array কে itarate করা ।

itarate.js
const arr = [1, 2, 3, 4, 5, 6, 7];
for (item of arr) {
    console.log(item);
}
//Output: 1 2 3 4 5 6 7

String কে itarate করা ।

itarate.js
const str = "Bangladesh";
for (character of str) {
    console.log(character);
}
 
// Output : B a n g l a d e s h

Asyncronus JavaScript

জাভাস্ক্রিপ্ট হলো সিঙ্গেল থ্রেডেড প্রোগ্রামিং ল্যাঙ্গুয়েজ