আগের পর্বে আমরা Destructuring শিখেছিলাম। এই পর্বে আমরা দেখব ... (তিনটা বিন্দু) — একই সিনট্যাক্স, কিন্তু দুটো সম্পূর্ণ বিপরীত কাজে ব্যবহার হয়: Spread (ছড়িয়ে দেওয়া) আর Rest (বাকিটা জড়ো করা)।
Spread বনাম Rest — পার্থক্য কোথায়?
দেখতে একই রকম হলেও এদের কাজ বিপরীত:
| অপারেটর | কাজ | কোথায় ব্যবহার হয় |
|---|---|---|
| Spread | একটা অ্যারে/অবজেক্টকে "ছড়িয়ে" আলাদা আলাদা মান বানায় | ফাংশন কল, অ্যারে/অবজেক্ট লিটারেলের ভেতরে |
| Rest | একাধিক আলাদা মানকে একটা অ্যারে/অবজেক্টে "জড়ো" করে | ফাংশন প্যারামিটার, Destructuring-এর শেষে |
Spread — Array-তে
একটা অ্যারের সব উপাদান আরেকটা অ্যারেতে "ছড়িয়ে" দেওয়া যায়:
const fruits = ["আম", "কাঁঠাল"]; const vegetables = ["আলু", "পটল"]; // দুটো অ্যারে মিলিয়ে নতুন একটা বানানো const all = [...fruits, ...vegetables]; console.log(all); // ["আম", "কাঁঠাল", "আলু", "পটল"] // অ্যারে কপি করা (আসল অ্যারে বদলে যাবে না) const fruitsCopy = [...fruits]; // মাঝখানে নতুন আইটেম যোগ করা const withNew = ["কলা", ...fruits, "লিচু"]; console.log(withNew); // ["কলা", "আম", "কাঁঠাল", "লিচু"]
Spread — Object-এ
অবজেক্টের প্রপার্টি মিলিয়ে নতুন অবজেক্ট বানানো, বা পুরনো অবজেক্ট থেকে কিছু প্রপার্টি পাল্টে নতুন অবজেক্ট বানানো (মূল অবজেক্ট না বদলে) খুব সাধারণ একটা প্যাটার্ন:
const user = { name: "আরিফ", age: 28 };
// একটা প্রপার্টি পাল্টে নতুন অবজেক্ট বানানো (মূল user অপরিবর্তিত থাকবে)
const updatedUser = { ...user, age: 29 };
console.log(updatedUser); // { name: "আরিফ", age: 29 }
console.log(user); // { name: "আরিফ", age: 28 } — এখনো আগেরটাই
// নতুন প্রপার্টি যোগ করা
const userWithRole = { ...user, role: "admin" };
// দুটো অবজেক্ট মার্জ করা (পরেরটা আগেরটার উপর override করে)
const defaults = { theme: "light", fontSize: 14 };
const customSettings = { theme: "dark" };
const finalSettings = { ...defaults, ...customSettings };
console.log(finalSettings); // { theme: "dark", fontSize: 14 }
গুরুত্বপূর্ণ প্যাটার্ন: { ...user, age: 29 } — এখানে মূল user অবজেক্ট সরাসরি না পাল্টে একটা নতুন অবজেক্ট বানানো হচ্ছে। এই "immutable update" প্যাটার্নটা React state আপডেট করার সময় সবচেয়ে বেশি ব্যবহার হয়।
Spread — ফাংশন কলে
একটা অ্যারেকে আলাদা আলাদা আর্গুমেন্ট হিসেবে পাঠাতে চাইলে:
function sum(a, b, c) {
return a + b + c;
}
const numbers = [10, 20, 30];
console.log(sum(...numbers)); // 60 — একই sum(10, 20, 30) হিসেবে কল হচ্ছে
// Math.max-এর সাথে খুব উপকারী, কারণ এটা অ্যারে সরাসরি নেয় না
console.log(Math.max(...numbers)); // 30
Rest — ফাংশন প্যারামিটারে
যখন কতগুলো আর্গুমেন্ট আসবে সেটা আগে থেকে জানা নেই, Rest দিয়ে সবগুলো একটা অ্যারেতে জড়ো করা যায়:
function sumAll(...numbers) {
// numbers এখন একটা সাধারণ অ্যারে, যত ইচ্ছা আর্গুমেন্ট নিতে পারবে
return numbers.reduce((total, n) => total + n, 0);
}
console.log(sumAll(1, 2, 3)); // 6
console.log(sumAll(1, 2, 3, 4, 5)); // 15
console.log(sumAll()); // 0
প্রথম কয়েকটা প্যারামিটার আলাদা রেখে বাকিগুলো Rest দিয়ে জড়ো করাও যায়:
function introduce(name, ...hobbies) {
console.log(`${name}-এর শখ: ${hobbies.join(", ")}`);
}
introduce("আরিফ", "কোডিং", "লেখালেখি", "ফটোগ্রাফি");
// আরিফ-এর শখ: কোডিং, লেখালেখি, ফটোগ্রাফি
নিয়ম: Rest প্যারামিটার সবসময় সবার শেষে থাকতে হবে — function bad(...rest, name) লিখলে Syntax Error হবে।
Rest — Destructuring-এর সাথে
আগের পর্বে শেখা Destructuring-এর সাথে মিলিয়ে "বাকি সবকিছু" ধরে রাখা যায়:
// Array-তে
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// Object-এ
const user = { name: "আরিফ", age: 28, city: "ঢাকা", role: "admin" };
const { name, ...otherInfo } = user;
console.log(name); // আরিফ
console.log(otherInfo); // { age: 28, city: "ঢাকা", role: "admin" }
লাইভ ডেমো — Spread দিয়ে অবজেক্ট আপডেট
নিচের ফর্ম পূরণ করে বাটনে চাপো — মূল অবজেক্ট অপরিবর্তিত রেখে Spread দিয়ে একটা নতুন, আপডেট করা অবজেক্ট বানানো দেখো।
সতর্কতা — Spread শুধু "shallow copy" করে
Spread দিয়ে কপি করলে শুধু উপরের লেভেলের প্রপার্টিগুলো কপি হয় — ভেতরের nested অবজেক্ট/অ্যারে এখনো একই রেফারেন্স শেয়ার করে।
const original = {
name: "আরিফ",
address: { city: "ঢাকা" }
};
const copy = { ...original };
copy.address.city = "চট্টগ্রাম"; // ভেতরের অবজেক্ট পাল্টে দিচ্ছি
console.log(original.address.city); // "চট্টগ্রাম" — মূলটাও বদলে গেছে!
// কারণ copy.address আর original.address একই অবজেক্টকে রেফার করে
সমাধান: Nested অবজেক্টও আলাদা করে কপি করতে হবে ({ ...original, address: { ...original.address } }), অথবা structuredClone() ব্যবহার করতে হবে যদি সম্পূর্ণ deep copy দরকার হয়।
একটা সম্পূর্ণ উদাহরণ — To-do লিস্ট আইটেম টগল করা
চলো Spread ব্যবহার করে একটা to-do লিস্টে একটা আইটেমের "সম্পন্ন" স্ট্যাটাস টগল করি, বাকি আইটেম অপরিবর্তিত রেখে — এটা React-স্টাইল state আপডেটের একটা সাধারণ প্যাটার্ন।
const todos = [
{ id: 1, text: "বাজার করা", done: false },
{ id: 2, text: "কোড রিভিউ", done: false },
{ id: 3, text: "পোস্ট পাবলিশ", done: true }
];
function toggleTodo(todos, id) {
return todos.map((todo) =>
todo.id === id
? { ...todo, done: !todo.done } // এই আইটেমটা নতুন অবজেক্ট, done উল্টানো
: todo // বাকিগুলো একইরকম থাকবে
);
}
const updatedTodos = toggleTodo(todos, 2);
console.log(updatedTodos);
// [
// { id: 1, text: "বাজার করা", done: false },
// { id: 2, text: "কোড রিভিউ", done: true }, ← শুধু এটা পাল্টেছে
// { id: 3, text: "পোস্ট পাবলিশ", done: true }
// ]
console.log(todos === updatedTodos); // false — সম্পূর্ণ নতুন অ্যারে
console.log(todos[0] === updatedTodos[0]); // true — অপরিবর্তিত আইটেম একই রেফারেন্স
এই প্যাটার্নটা গুরুত্বপূর্ণ কারণ এটা মূল todos অ্যারে না পাল্টে একটা নতুন অ্যারে রিটার্ন করছে — এই "immutability" ধারণাটা আধুনিক ফ্রেমওয়ার্ক (React, Vue) আর স্টেট ম্যানেজমেন্টে অত্যন্ত গুরুত্বপূর্ণ।
নিজে চেষ্টা করো
Exercise:
- দুটো অ্যারে মার্জ করে ডুপ্লিকেট মুছে ফেলো — হিন্ট:
[...new Set([...arr1, ...arr2])]। - একটা ফাংশন লিখো যেটা যেকোনো সংখ্যক আর্গুমেন্ট নিয়ে সবচেয়ে বড়টা রিটার্ন করবে (Rest ব্যবহার করে)।
- উপরের
toggleTodoফাংশনটা নিজে লিখো, তারপর একটাdeleteTodo(todos, id)ফাংশনও বানাও যেটা Spread/Rest ব্যবহার করে একটা আইটেম বাদ দিয়ে নতুন অ্যারে বানাবে (হিন্ট:filterব্যবহার করা যায়)। - একটা nested অবজেক্ট নিয়ে "shallow copy বাগ" নিজে তৈরি করো, তারপর সেটা ঠিক করার চেষ্টা করো।
পরের পর্বে যা থাকছে
পরের পর্বে আমরা শিখব Promise বিস্তারিত — Promise.all, Promise.race, আর Promise.allSettled দিয়ে একাধিক অ্যাসিনক্রোনাস কাজ কীভাবে সামলানো যায়।