ES6+ Advanced JavaScript - Complete Mastery Guide
Node.js এর আসল শক্তি ব্যবহার করতে হলে Modern JavaScript (ES6+) ফিচারগুলো বোঝা অত্যন্ত জরুরি। এই guide এ আমরা ES2015 (ES6) থেকে শুরু করে ES2023 পর্যন্ত সব modern features শিখব।
Why Learn ES6+?
Before ES6 (ES5):
- var (function scope, hoisting issues)
- callbacks (callback hell)
- for loops (verbose)
- string concatenation (messy)
- Object manipulation (limited)
After ES6+ (Modern JavaScript):
✅ let/const (block scope)
✅ async/await (clean async code)
✅ Array methods (map, filter, reduce)
✅ Template literals (easy strings)
✅ Destructuring (elegant syntax)
✅ Spread/Rest operators
✅ Arrow functions
✅ Classes
✅ Modules
✅ Promises
✅ And much more!Table of Contents
- Promises - Async operations foundation
- Async/Await - Clean async code
- Arrow Functions - Concise function syntax
- Destructuring - Extract values elegantly
- Spread/Rest Operators - Array/Object manipulation
- Template Literals - String formatting
- Enhanced Object Literals - Object creation shortcuts
- Classes & OOP - Object-oriented programming
- Modules - Code organization
- Array Methods - map, filter, reduce, etc.
- Higher-Order Functions - Functions as values
- Closures - Lexical scoping
- This Keyword - Context binding
- Prototypes - Inheritance mechanism
- Symbol - Unique identifiers
- Iterators & Generators - Custom iteration
- Proxy & Reflect - Metaprogramming
- WeakMap & WeakSet - Weak references
- Optional Chaining - Safe property access
- Nullish Coalescing - Default values
- Error Handling - try/catch/finally
- Best Practices - Modern JavaScript patterns
১. Promises - Complete Deep Dive
Promise হলো JavaScript এর asynchronous programming এর foundation। এটি "ভবিষ্যতে কোনো একটি value পাওয়ার প্রতিশ্রুতি"।
Promise States
Promise এর 3টি state থাকে:
┌─────────────────────────────────────────┐
│ PENDING (Initial) │
│ (কাজ চলছে, waiting...) │
└─────────────┬───────────────────────────┘
│
┌──────┴──────┐
│ │
▼ ▼
┌─────────┐ ┌──────────┐
│FULFILLED│ │ REJECTED │
│(Success)│ │ (Failed) │
└─────────┘ └──────────┘Creating Promises
// Basic Promise
const myPromise = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve("Operation Successful! ✅"); // Fulfilled
} else {
reject("Operation Failed! ❌"); // Rejected
}
});
// Consuming Promise
myPromise
.then((message) => console.log(message)) // Handle success
.catch((error) => console.error(error)) // Handle error
.finally(() => console.log('Done!')); // Always runsReal-World Example
// Simulating API call
function fetchUser(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId > 0) {
resolve({ id: userId, name: 'John Doe', email: 'john@example.com' });
} else {
reject(new Error('Invalid user ID'));
}
}, 1000);
});
}
// Usage
fetchUser(1)
.then(user => {
console.log('User found:', user);
return user.id; // Return value for next .then()
})
.then(userId => {
console.log('User ID:', userId);
})
.catch(error => {
console.error('Error:', error.message);
})
.finally(() => {
console.log('Fetch attempt completed');
});Promise Chaining
Multiple async operations কে sequential ভাবে execute করার জন্য।
// ❌ Callback Hell (Old way)
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
getYetMoreData(c, function(d) {
console.log(d);
});
});
});
});
// ✅ Promise Chaining (Better)
getData()
.then(a => getMoreData(a))
.then(b => getEvenMoreData(b))
.then(c => getYetMoreData(c))
.then(d => console.log(d))
.catch(error => console.error(error));Important Rules:
// ✅ Return value for next .then()
promise
.then(result => {
return result * 2; // Must return!
})
.then(doubled => {
console.log(doubled);
});
// ❌ Forgetting return breaks the chain
promise
.then(result => {
result * 2; // No return! Next .then() gets undefined
})
.then(doubled => {
console.log(doubled); // undefined 😱
});
// ✅ Return Promise for async operations
fetchUser(1)
.then(user => {
return fetchPosts(user.id); // Return Promise
})
.then(posts => {
console.log(posts);
});Promise Static Methods
1. Promise.all() - Wait for all to complete
// All promises must succeed
const promise1 = Promise.resolve(3);
const promise2 = Promise.resolve(42);
const promise3 = new Promise((resolve) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log(values); // [3, 42, 'foo']
});
// If any fails, entire Promise.all fails
const p1 = Promise.resolve(1);
const p2 = Promise.reject('Error!'); // This fails
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3])
.then(values => {
console.log(values); // Never runs
})
.catch(error => {
console.error(error); // 'Error!' - stops at first failure
});Real-World Use Case:
// Fetch multiple users in parallel
async function fetchMultipleUsers(userIds) {
const promises = userIds.map(id => fetchUser(id));
try {
const users = await Promise.all(promises);
console.log('All users:', users);
} catch (error) {
console.error('Failed to fetch users:', error);
}
}
fetchMultipleUsers([1, 2, 3, 4, 5]);2. Promise.allSettled() - Wait for all to complete (success or failure)
// Returns all results regardless of success/failure
const p1 = Promise.resolve(1);
const p2 = Promise.reject('Error!');
const p3 = Promise.resolve(3);
Promise.allSettled([p1, p2, p3])
.then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'Error!' },
// { status: 'fulfilled', value: 3 }
// ]
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${index} succeeded:`, result.value);
} else {
console.log(`Promise ${index} failed:`, result.reason);
}
});
});Use Case: Multiple API calls where some may fail
async function fetchAllData() {
const results = await Promise.allSettled([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments') // May fail
]);
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
console.log('Successful requests:', successful.length);
}3. Promise.race() - First to complete wins
// Returns the first promise to settle (fulfilled or rejected)
const p1 = new Promise((resolve) => setTimeout(resolve, 500, 'one'));
const p2 = new Promise((resolve) => setTimeout(resolve, 100, 'two'));
Promise.race([p1, p2])
.then(value => {
console.log(value); // 'two' (faster)
});Use Case: Timeout implementation
function timeout(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout!')), ms);
});
}
function fetchWithTimeout(url, ms) {
return Promise.race([
fetch(url),
timeout(ms)
]);
}
// Fetch with 5 second timeout
fetchWithTimeout('/api/data', 5000)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
if (error.message === 'Timeout!') {
console.error('Request timed out!');
} else {
console.error('Request failed:', error);
}
});4. Promise.any() - First successful promise
// Returns first fulfilled promise (ignores rejections)
const p1 = Promise.reject('Error 1');
const p2 = Promise.reject('Error 2');
const p3 = Promise.resolve('Success!');
const p4 = Promise.resolve('Also success!');
Promise.any([p1, p2, p3, p4])
.then(value => {
console.log(value); // 'Success!' (first to fulfill)
})
.catch(error => {
console.error(error); // Only if all reject
});Use Case: Multiple API endpoints (fallback)
// Try multiple CDNs, use first successful
Promise.any([
fetch('https://cdn1.example.com/library.js'),
fetch('https://cdn2.example.com/library.js'),
fetch('https://cdn3.example.com/library.js')
])
.then(response => response.text())
.then(script => {
console.log('Loaded from fastest CDN');
})
.catch(error => {
console.error('All CDNs failed!');
});5. Promise.resolve() & Promise.reject()
// Create immediately resolved promise
const resolved = Promise.resolve(42);
resolved.then(value => console.log(value)); // 42
// Create immediately rejected promise
const rejected = Promise.reject('Error!');
rejected.catch(error => console.error(error)); // 'Error!'
// Useful for wrapping values in promises
function getData(value) {
if (value) {
return Promise.resolve(value);
} else {
return Promise.reject('No value provided');
}
}Promise Error Handling
// Method 1: .catch() at the end
fetchUser(1)
.then(user => fetchPosts(user.id))
.then(posts => fetchComments(posts[0].id))
.catch(error => {
console.error('Error in chain:', error);
});
// Method 2: Multiple .catch() blocks
fetchUser(1)
.then(user => fetchPosts(user.id))
.catch(error => {
console.error('Error fetching posts:', error);
return []; // Provide default value
})
.then(posts => {
console.log('Posts:', posts);
});
// Method 3: Error recovery
fetchUser(1)
.catch(error => {
console.warn('Primary fetch failed, trying backup');
return fetchUserFromBackup(1); // Fallback
})
.then(user => {
console.log('User (from primary or backup):', user);
});
// Method 4: Re-throwing errors
fetchUser(1)
.catch(error => {
console.error('Error:', error);
throw error; // Re-throw for outer handler
})
.then(user => {
console.log(user);
})
.catch(error => {
console.error('Outer catch:', error);
});Promise Best Practices
// ✅ Good: Always return in .then()
promise
.then(result => {
return processResult(result); // Return for next .then()
})
.then(processed => {
console.log(processed);
});
// ✅ Good: Always add .catch()
promise
.then(result => console.log(result))
.catch(error => console.error(error));
// ✅ Good: Use .finally() for cleanup
fetchData()
.then(data => processData(data))
.catch(error => console.error(error))
.finally(() => {
hideLoadingSpinner(); // Always runs
closeConnection();
});
// ❌ Bad: Nested promises (promise hell)
fetchUser(1)
.then(user => {
fetchPosts(user.id)
.then(posts => {
fetchComments(posts[0].id)
.then(comments => {
console.log(comments);
});
});
});
// ✅ Good: Flat chain
fetchUser(1)
.then(user => fetchPosts(user.id))
.then(posts => fetchComments(posts[0].id))
.then(comments => console.log(comments))
.catch(error => console.error(error));
// ❌ Bad: Not handling errors
promise.then(result => console.log(result)); // Unhandled rejection!
// ✅ Good: Always handle errors
promise
.then(result => console.log(result))
.catch(error => console.error(error));Promisifying Callback-based Functions
// Old callback-based function
function oldStyleAsync(value, callback) {
setTimeout(() => {
if (value > 0) {
callback(null, value * 2);
} else {
callback(new Error('Invalid value'));
}
}, 1000);
}
// ❌ Using callbacks (old way)
oldStyleAsync(5, (error, result) => {
if (error) {
console.error(error);
} else {
console.log(result);
}
});
// ✅ Promisify it
function promisifiedAsync(value) {
return new Promise((resolve, reject) => {
oldStyleAsync(value, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
// Now use with promises
promisifiedAsync(5)
.then(result => console.log(result))
.catch(error => console.error(error));
// Or use Node.js util.promisify
const util = require('util');
const promisified = util.promisify(oldStyleAsync);২. Async / Await - Modern Async Programming
async/await হলো Promise এর উপর built একটি syntactic sugar যা async code কে synchronous এর মতো দেখতে এবং লিখতে সাহায্য করে।
Basic Syntax
// async function always returns a Promise
async function myFunction() {
return 'Hello'; // Automatically wrapped in Promise.resolve()
}
myFunction().then(value => console.log(value)); // 'Hello'
// await pauses execution until Promise resolves
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}Promises vs Async/Await
// ❌ Using Promises (more verbose)
function getUserPosts() {
return fetchUser(1)
.then(user => {
console.log('User:', user);
return fetchPosts(user.id);
})
.then(posts => {
console.log('Posts:', posts);
return fetchComments(posts[0].id);
})
.then(comments => {
console.log('Comments:', comments);
return comments;
})
.catch(error => {
console.error('Error:', error);
throw error;
});
}
// ✅ Using Async/Await (cleaner)
async function getUserPosts() {
try {
const user = await fetchUser(1);
console.log('User:', user);
const posts = await fetchPosts(user.id);
console.log('Posts:', posts);
const comments = await fetchComments(posts[0].id);
console.log('Comments:', comments);
return comments;
} catch (error) {
console.error('Error:', error);
throw error;
}
}Error Handling
// Method 1: try-catch (recommended)
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching data:', error);
throw error; // Re-throw or handle
}
}
// Method 2: .catch() on individual await
async function fetchData() {
const data = await fetch('/api/data')
.catch(error => {
console.error('Fetch failed:', error);
return null; // Provide default
});
if (data) {
return await data.json();
}
}
// Method 3: Wrapper function
async function handle(promise) {
try {
const data = await promise;
return [data, null];
} catch (error) {
return [null, error];
}
}
// Usage
const [data, error] = await handle(fetch('/api/data'));
if (error) {
console.error('Error:', error);
} else {
console.log('Data:', data);
}Parallel Execution
// ❌ Sequential (slow - 3 seconds)
async function fetchAllSequential() {
const user = await fetchUser(1); // 1 second
const posts = await fetchPosts(1); // 1 second
const comments = await fetchComments(1); // 1 second
// Total: 3 seconds
return { user, posts, comments };
}
// ✅ Parallel (fast - 1 second)
async function fetchAllParallel() {
const [user, posts, comments] = await Promise.all([
fetchUser(1),
fetchPosts(1),
fetchComments(1)
]);
// Total: 1 second (all execute simultaneously)
return { user, posts, comments };
}
// ✅ Parallel with Promise.allSettled (handles failures)
async function fetchAllSafe() {
const results = await Promise.allSettled([
fetchUser(1),
fetchPosts(1),
fetchComments(1)
]);
const [userResult, postsResult, commentsResult] = results;
return {
user: userResult.status === 'fulfilled' ? userResult.value : null,
posts: postsResult.status === 'fulfilled' ? postsResult.value : null,
comments: commentsResult.status === 'fulfilled' ? commentsResult.value : null
};
}Real-World Examples
1. API with Error Handling
async function createUser(userData) {
try {
// Validate data
if (!userData.email) {
throw new Error('Email is required');
}
// Check if user exists
const existing = await User.findOne({ email: userData.email });
if (existing) {
throw new Error('User already exists');
}
// Hash password
const hashedPassword = await bcrypt.hash(userData.password, 10);
// Create user
const user = await User.create({
...userData,
password: hashedPassword
});
// Send welcome email
await sendEmail(user.email, 'Welcome!');
return user;
} catch (error) {
console.error('Failed to create user:', error);
throw error;
}
}2. Database Transactions
async function transferMoney(senderId, receiverId, amount) {
const session = await mongoose.startSession();
session.startTransaction();
try {
// Deduct from sender
const sender = await Account.findById(senderId).session(session);
if (sender.balance < amount) {
throw new Error('Insufficient balance');
}
sender.balance -= amount;
await sender.save();
// Add to receiver
const receiver = await Account.findById(receiverId).session(session);
receiver.balance += amount;
await receiver.save();
// Commit transaction
await session.commitTransaction();
console.log('Transfer successful');
return { success: true };
} catch (error) {
// Rollback transaction
await session.abortTransaction();
console.error('Transfer failed:', error);
throw error;
} finally {
session.endSession();
}
}3. API Request with Timeout
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeoutId);
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Request timed out');
}
throw error;
}
}
// Usage
try {
const data = await fetchWithTimeout('/api/data', 3000);
console.log(data);
} catch (error) {
console.error('Error:', error.message);
}4. Retry Logic
async function retryOperation(operation, maxRetries = 3, delay = 1000) {
for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (error) {
if (i === maxRetries - 1) {
throw error; // Last attempt failed
}
console.log(`Attempt ${i + 1} failed, retrying...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Usage
try {
const data = await retryOperation(() => fetch('/api/data'));
console.log('Success:', data);
} catch (error) {
console.error('All retries failed:', error);
}Async/Await Best Practices
// ✅ Good: Always use try-catch
async function goodAsync() {
try {
const data = await fetchData();
return data;
} catch (error) {
console.error(error);
throw error;
}
}
// ❌ Bad: No error handling
async function badAsync() {
const data = await fetchData(); // Unhandled rejection!
return data;
}
// ✅ Good: Parallel execution when possible
async function goodParallel() {
const [users, posts] = await Promise.all([
fetchUsers(),
fetchPosts()
]);
}
// ❌ Bad: Unnecessary sequential execution
async function badSequential() {
const users = await fetchUsers(); // Waits
const posts = await fetchPosts(); // Then waits again
}
// ✅ Good: Top-level await (ES2022, in modules)
const data = await fetchData(); // In module scope
// ✅ Good: Named async functions for stack traces
async function namedFunction() {
await fetchData();
}
// ❌ Bad: Anonymous async functions
const anonymous = async () => {
await fetchData(); // Harder to debug
};
// ✅ Good: Return await in try-catch
async function goodReturn() {
try {
return await fetchData(); // Catch errors here
} catch (error) {
console.error(error);
}
}
// ❌ Bad: Return promise without await
async function badReturn() {
try {
return fetchData(); // Errors not caught!
} catch (error) {
console.error(error);
}
}Common Mistakes
// ❌ Mistake 1: Forgetting await
async function mistake1() {
const data = fetchData(); // Returns Promise, not data!
console.log(data); // Promise { <pending> }
}
// ✅ Correct
async function correct1() {
const data = await fetchData();
console.log(data); // Actual data
}
// ❌ Mistake 2: Sequential when should be parallel
async function mistake2() {
const user = await fetchUser(1);
const posts = await fetchPosts(1);
// Both are independent, should run in parallel!
}
// ✅ Correct
async function correct2() {
const [user, posts] = await Promise.all([
fetchUser(1),
fetchPosts(1)
]);
}
// ❌ Mistake 3: Using await in loops (slow)
async function mistake3(ids) {
const results = [];
for (const id of ids) {
results.push(await fetchData(id)); // Sequential!
}
return results;
}
// ✅ Correct
async function correct3(ids) {
const promises = ids.map(id => fetchData(id));
return await Promise.all(promises); // Parallel!
}
// ❌ Mistake 4: Not handling errors
async function mistake4() {
const data = await fetchData(); // What if this fails?
return data;
}
// ✅ Correct
async function correct4() {
try {
const data = await fetchData();
return data;
} catch (error) {
console.error('Error:', error);
throw error;
}
}৩. Arrow Functions - Concise Syntax
Arrow functions হলো function expression এর একটি shorter syntax।
Basic Syntax
// Traditional function
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => {
return a + b;
};
// Implicit return (single expression)
const add = (a, b) => a + b;
// Single parameter (no parentheses needed)
const double = x => x * 2;
// No parameters
const greet = () => console.log('Hello!');
// Object return (wrap in parentheses)
const getPerson = () => ({ name: 'John', age: 30 });Arrow Function vs Regular Function
// 1. 'this' binding
// Regular function: 'this' depends on how it's called
const obj1 = {
name: 'John',
regularFunc: function() {
console.log(this.name); // 'John'
}
};
// Arrow function: 'this' is lexically bound
const obj2 = {
name: 'John',
arrowFunc: () => {
console.log(this.name); // undefined (inherits outer 'this')
}
};
// 2. Cannot be used as constructor
const RegularFunc = function() {
this.value = 42;
};
const instance = new RegularFunc(); // ✅ Works
const ArrowFunc = () => {
this.value = 42;
};
const instance2 = new ArrowFunc(); // ❌ TypeError
// 3. No arguments object
function regularFunc() {
console.log(arguments); // [1, 2, 3]
}
regularFunc(1, 2, 3);
const arrowFunc = () => {
console.log(arguments); // ReferenceError
};
// Use rest parameters instead
const arrowFunc2 = (...args) => {
console.log(args); // [1, 2, 3]
};When to Use Arrow Functions
// ✅ Good: Callbacks
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
// ✅ Good: Promise chains
fetchData()
.then(data => processData(data))
.then(result => console.log(result));
// ✅ Good: Event handlers where you need outer 'this'
class Counter {
constructor() {
this.count = 0;
}
start() {
setInterval(() => {
this.count++; // 'this' refers to Counter instance
console.log(this.count);
}, 1000);
}
}
// ❌ Bad: Object methods (need 'this')
const person = {
name: 'John',
sayHi: () => {
console.log(`Hi, I'm ${this.name}`); // 'this' is undefined!
}
};
// ✅ Good: Object methods with regular function
const person2 = {
name: 'John',
sayHi() {
console.log(`Hi, I'm ${this.name}`); // Works!
}
};৪. Destructuring - Extract Values Elegantly
Destructuring allows unpacking values from arrays or properties from objects into distinct variables।
Array Destructuring
// Basic
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a, b, c); // 1 2 3
// Skip elements
const [first, , third] = [1, 2, 3];
console.log(first, third); // 1 3
// Rest operator
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
// Default values
const [x = 0, y = 0] = [1];
console.log(x, y); // 1 0
// Swapping variables
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
// Function return values
function getCoordinates() {
return [10, 20];
}
const [x, y] = getCoordinates();Object Destructuring
// Basic
const person = { name: 'John', age: 30, city: 'NYC' };
const { name, age, city } = person;
console.log(name, age, city); // John 30 NYC
// Rename variables
const { name: fullName, age: years } = person;
console.log(fullName, years); // John 30
// Default values
const { name, country = 'USA' } = person;
console.log(country); // USA
// Nested destructuring
const user = {
id: 1,
name: 'John',
address: {
street: '123 Main St',
city: 'NYC'
}
};
const { name, address: { street, city } } = user;
console.log(street, city); // 123 Main St NYC
// Rest operator
const { name, ...rest } = person;
console.log(rest); // { age: 30, city: 'NYC' }
// Function parameters
function displayUser({ name, age, city = 'Unknown' }) {
console.log(`${name}, ${age}, from ${city}`);
}
displayUser(person); // John, 30, from NYCReal-World Examples
// API response
async function getUser(id) {
const response = await fetch(`/api/users/${id}`);
const { data: { name, email, profile: { avatar } } } = await response.json();
return { name, email, avatar };
}
// React props
function UserCard({ user: { name, email, avatar }, onDelete }) {
return (
<div>
<img src={avatar} />
<h2>{name}</h2>
<p>{email}</p>
<button onClick={onDelete}>Delete</button>
</div>
);
}
// Array methods
const users = [
{ id: 1, name: 'John', age: 30 },
{ id: 2, name: 'Jane', age: 25 },
{ id: 3, name: 'Bob', age: 35 }
];
// Extract specific fields
const names = users.map(({ name }) => name);
console.log(names); // ['John', 'Jane', 'Bob']
// Filter with destructuring
const adults = users.filter(({ age }) => age >= 30);৫. Spread/Rest Operators - Array/Object Manipulation
Spread (...) এবং Rest (...) operators একই syntax ব্যবহার করে কিন্তু different contexts এ different কাজ করে।
Spread Operator (...)
Array Spreading
// Copy array
const arr1 = [1, 2, 3];
const arr2 = [...arr1]; // Shallow copy
arr2.push(4);
console.log(arr1); // [1, 2, 3] (unchanged)
console.log(arr2); // [1, 2, 3, 4]
// Concatenate arrays
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4]
// Add elements
const arr = [2, 3];
const newArr = [1, ...arr, 4, 5]; // [1, 2, 3, 4, 5]
// Convert string to array
const str = 'hello';
const chars = [...str]; // ['h', 'e', 'l', 'l', 'o']
// Function arguments
const numbers = [1, 2, 3];
console.log(Math.max(...numbers)); // 3
// Remove duplicates
const arr = [1, 2, 2, 3, 3, 4];
const unique = [...new Set(arr)]; // [1, 2, 3, 4]Object Spreading
// Copy object
const obj1 = { name: 'John', age: 30 };
const obj2 = { ...obj1 }; // Shallow copy
// Merge objects
const defaults = { theme: 'light', fontSize: 14 };
const userPrefs = { fontSize: 16, color: 'blue' };
const settings = { ...defaults, ...userPrefs };
// { theme: 'light', fontSize: 16, color: 'blue' }
// Add/Update properties
const user = { name: 'John', age: 30 };
const updatedUser = { ...user, age: 31, city: 'NYC' };
// { name: 'John', age: 31, city: 'NYC' }
// Conditional properties
const showEmail = true;
const user = {
name: 'John',
...(showEmail && { email: 'john@example.com' })
};Rest Operator (...)
Function Parameters
// Collect remaining arguments
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// Mix with regular parameters
function greet(greeting, ...names) {
return `${greeting} ${names.join(', ')}!`;
}
console.log(greet('Hello', 'John', 'Jane', 'Bob'));
// "Hello John, Jane, Bob!"Destructuring
// Array rest
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// Object rest
const { name, age, ...otherInfo } = {
name: 'John',
age: 30,
city: 'NYC',
country: 'USA'
};
console.log(otherInfo); // { city: 'NYC', country: 'USA' }Real-World Examples
// Immutable updates (React/Redux)
const state = { users: [], loading: false };
// Add user
const newState = {
...state,
users: [...state.users, newUser]
};
// Update user
const updatedState = {
...state,
users: state.users.map(user =>
user.id === id ? { ...user, ...updates } : user
)
};
// API wrapper
async function api(endpoint, { method = 'GET', ...options } = {}) {
const response = await fetch(endpoint, {
method,
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
});
return response.json();
}
// Component props forwarding (React)
function Button({ onClick, children, ...props }) {
return (
<button onClick={onClick} {...props}>
{children}
</button>
);
}
// Usage
<Button onClick={handleClick} className="btn" disabled>
Click me
</Button>৬. Template Literals - Modern String Formatting
Template literals allow embedded expressions এবং multi-line strings।
Basic Syntax
// Old way (concatenation)
const name = 'John';
const age = 30;
const message = 'My name is ' + name + ' and I am ' + age + ' years old.';
// New way (template literals)
const message = `My name is ${name} and I am ${age} years old.`;Features
// 1. Multi-line strings
const multiLine = `
This is line 1
This is line 2
This is line 3
`;
// 2. Expression interpolation
const a = 5;
const b = 10;
console.log(`Sum: ${a + b}`); // Sum: 15
// 3. Function calls
function upper(str) {
return str.toUpperCase();
}
console.log(`Hello ${upper('world')}!`); // Hello WORLD!
// 4. Nested templates
const user = { name: 'John', isAdmin: true };
const message = `User ${user.name} is ${user.isAdmin ? `an admin` : `not an admin`}`;
// 5. Tagged templates (advanced)
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
return `${result}${str}<strong>${values[i] || ''}</strong>`;
}, '');
}
const name = 'John';
const age = 30;
const html = highlight`Name: ${name}, Age: ${age}`;
// "Name: <strong>John</strong>, Age: <strong>30</strong>"Real-World Examples
// HTML templates
function createUserCard(user) {
return `
<div class="user-card">
<img src="${user.avatar}" alt="${user.name}" />
<h2>${user.name}</h2>
<p>${user.email}</p>
<span class="badge">${user.role}</span>
</div>
`;
}
// SQL queries (with proper escaping!)
function buildQuery(table, filters) {
const where = Object.entries(filters)
.map(([key, value]) => `${key} = '${value}'`)
.join(' AND ');
return `SELECT * FROM ${table} WHERE ${where}`;
}
// API URLs
const userId = 123;
const endpoint = `/api/users/${userId}/posts?limit=10&sort=desc`;
// Logging
console.log(`[${new Date().toISOString()}] User ${userId} logged in`);৭. Enhanced Object Literals
ES6 এ object creation এর জন্য shorthand syntax এসেছে।
// 1. Property shorthand
const name = 'John';
const age = 30;
// Old way
const person = {
name: name,
age: age
};
// New way
const person = { name, age };
// 2. Method shorthand
// Old way
const person = {
sayHi: function() {
console.log('Hi!');
}
};
// New way
const person = {
sayHi() {
console.log('Hi!');
}
};
// 3. Computed property names
const propName = 'age';
const person = {
name: 'John',
[propName]: 30, // age: 30
[`is${propName}Valid`]: true // isageValid: true
};
// 4. Dynamic keys
function createObject(key, value) {
return { [key]: value };
}
const obj = createObject('name', 'John'); // { name: 'John' }
// Real-world example: Form data
function handleSubmit(event) {
const formData = {
[event.target.name]: event.target.value,
timestamp: Date.now()
};
}