আপনি তিনটি ফাইল জুড়ে একটি বাগ (bug) খুঁজছেন এবং শেষে দেখলেন যে একটি নিরীহ হেল্পার ফাংশন একজন ব্যবহারকারীর নাম পরিবর্তন করে ফেলেছে। আপনি মূল ফাইলটিতে হাতও দেননি। অন্তত আপনি তাই ভেবেছিলেন। JavaScript-এ একটি ভেরিয়েবলকে অন্যটিতে অ্যাসাইন (assign) করার মানে সবসময় আপনার প্রত্যাশা অনুযায়ী নাও হতে পারে। এই ল্যাঙ্গুয়েজটি তার ডেটাকে দুটি স্টোরেজ কৌশলে বিভক্ত করে, আর আপনি কোনটি ব্যবহার করছেন তা ভুলে যাওয়াই হলো প্রোডাকশন কোডে নিঃশব্দ মিউটেশন (silent mutation) আসার প্রধান কারণ।

এটি প্রতিরোধ করতে হলে, ইঞ্জিন যেভাবে দেখে ঠিক সেভাবেই আপনাকে প্রিমিটিভ ভ্যালু (primitive values) এবং অবজেক্টের (objects) মধ্যে পার্থক্য বুঝতে হবে।

Primitives: প্রকৃত কপি (Actual Copies)

একটি প্রিমিটিভ হলো একটি একক, অবিভাজ্য ডেটাম (datum)। এটিকে ছোট ছোট JavaScript ভ্যালুতে বিভক্ত করা যায় না। এই ল্যাঙ্গুয়েজটি সাতটি প্রিমিটিভ টাইপ সংজ্ঞায়িত করে: String, Number, Boolean, Undefined, Null, Symbol, এবং BigInt।

যেহেতু প্রিমিটিভগুলো অ্যাটমিক (atomic), তাই এগুলো সাধারণত সরাসরি ভেরিয়েবল বাইন্ডিংয়ের (variable binding) ভেতরে থাকে। যখন আপনি একটি প্রিমিটিভ ভেরিয়েবলকে অন্যটিতে কপি করেন, ইঞ্জিন প্রকৃত ডেটাটিকে ডুপ্লিকেট করে। প্রতিটি ভেরিয়েবল মেমরিতে তার নিজস্ব স্বতন্ত্র স্লট পায়।

let a = "Alina";
let b = a;
b = "Ali";

console.log(a); // "Alina"
console.log(b); // "Ali"

এখানে, a অপরিবর্তিত থাকে। b-কে পুনরায় অ্যাসাইন করার ফলে একটি সম্পূর্ণ নতুন ভ্যালু তৈরি হয়েছে এবং b সেই নতুন ভ্যালুটিকে নির্দেশ করছে, যেখানে a এখনও তার মূল স্ট্রিংটি ধরে রেখেছে। এই আচরণটি হলো copy by value। এটি নম্বর, বুলিয়ান, সিম্বল এবং অন্যান্য প্রিমিটিভ টাইপের ক্ষেত্রেও একইভাবে কাজ করে। আপনি পার্শ্ববর্তী ভেরিয়েবলগুলোর ওপর কোনো পার্শ্বপ্রতিক্রিয়া (side effects) হওয়ার চিন্তা না করেই এগুলো ফাংশনে পাস করতে পারেন, পুনরায় অ্যাসাইন করতে পারেন বা রিটার্ন করতে পারেন।

Objects: শেয়ার করা অ্যাড্রেস (Shared Addresses)

অবজেক্টগুলো ভিন্ন। একটি অবজেক্ট হলো একটি কম্পোজিট কন্টেইনার যা একাধিক ডেটাকে একত্রে গ্রুপ করে। এই ক্যাটাগরিতে রয়েছে plain objects, arrays, functions, dates এবং অন্যান্য সব নন-প্রিমিটিভ টাইপ। যেহেতু এই স্ট্রাকচারগুলো বড় এবং নেস্টেড (nested) হতে পারে, তাই JavaScript ভেরিয়েবলের ভেতরে পুরো অবজেক্টটি সংরক্ষণ করে না। পরিবর্তে, ভেরিয়েবলটি একটি রেফারেন্স (reference) ধারণ করে, যা মূলত অন্য কোথাও সংরক্ষিত প্রকৃত ডেটাকে নির্দেশকারী একটি মেমরি অ্যাড্রেস।

যখন আপনি একটি অবজেক্টকে নতুন একটি ভেরিয়েবলে অ্যাসাইন করেন, ইঞ্জিন অ্যাড্রেসটি কপি করে, অবজেক্টটিকে নয়। এখন দুটি ভেরিয়েবলই ঠিক একই বাড়িকে নির্দেশ করছে।

const user = { name: "Alina" };
const copy = user;
copy.name = "Ali";

console.log(user.name); // "Ali"

copy.name পরিবর্তন করার ফলে user.name-ও পরিবর্তিত হয়ে গেছে, কারণ উভয় নামই একই মূল অবজেক্টকে নির্দেশ করছে। এটি হলো copy by reference। অ্যারের ক্ষেত্রেও একই রকম বিস্ময়কর ঘটনা ঘটে:

const scores = [82, 91, 74];
const backup = scores;
backup.push(88);

console.log(scores); // [82, 91, 74, 88]

মেমরিতে কেবল একটি অ্যারে রয়েছে। scores এবং backup হলো কেবল দুটি চিহ্ন যা এটিকে নির্দেশ করছে।

const কিওয়ার্ডটি বিভ্রান্তির একটি স্তর যোগ করে। const দিয়ে একটি অবজেক্ট ডিক্লেয়ার করলে ভেরিয়েবল বাইন্ডিংটি লক হয়ে যায়, যাতে আপনি এটিকে নতুন কোনো অ্যাড্রেস নির্দেশ করতে না পারেন। তবে এটি অবজেক্টটিকে লক করে না।

const settings = { theme: "dark" };
settings.theme = "light";        // Works perfectly.
settings = { theme: "dark" };    // TypeError

ডেভেলপাররা প্রায়ই আশা করেন যে const ইমিউটেবিলিটি (immutability) নিশ্চিত করবে। কিন্তু এটি করে না। এটি কেবল রেফারেন্সের পুনরায় অ্যাসাইনমেন্ট রোধ করে। আপনি যদি এর ভেতরের বিষয়বস্তু সুরক্ষিত রাখতে চান, তবে আপনাকে উদ্দেশ্যমূলকভাবে কপি করতে হবে।

যেখানে আসল বাগগুলো লুকিয়ে থাকে

রেফারেন্স সংক্রান্ত বাগগুলো খুব কমই সরাসরি ভেরিয়েবল রিয়ারসাইনমেন্ট হিসেবে প্রকাশ পায়। এগুলো ফাংশন কলের ভেতরে লুকিয়ে থাকে।

function addTimestamp(record) {
  record.timestamp = Date.now();
  return record;
}

const original = { id: 1 };
addTimestamp(original);

console.log(original.timestamp); // A number now exists here. Oops.

record প্যারামিটারটি রেফারেন্সের একটি কপি পেয়েছে। ফাংশনের ভেতরে যেকোনো প্রপার্টি মিউটেশন (property mutation) সরাসরি কলারের (caller) অবজেক্টে লেখা হয়ে গেছে। ফাংশনটি দেখতে একটি সাধারণ ট্রান্সফরমেশনের মতো মনে হলেও, এটি স্কোপের সীমানার বাইরে স্টেট লিক (leak state) করে ফেলেছে।

এই প্যাটার্নটি React-এর মতো UI ফ্রেমওয়ার্কের ক্ষেত্রে বিশেষভাবে যন্ত্রণাদায়ক, যেখানে স্টেট আপডেট নির্ভর করে