Arrow functions are a concise syntax for writing function expressions in ES6. Here are the key differences:
Syntax Differences:
// Regular function
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => a + b;
// Multiple parameters
const multiply = (a, b) => {
return a * b;
};
// Single parameter (parentheses optional)
const square = x => x * x;
// No parameters
const getTime = () => new Date();
Key Differences:
thisBinding:
const obj = {
name: 'John',
regularFunction: function() {
console.log(this.name); // 'John' - this refers to obj
},
arrowFunction: () => {
console.log(this.name); // undefined - this refers to global/window
}
};
obj.regularFunction(); // 'John'
obj.arrowFunction(); // undefined
- Arguments Object:
function regularFunction() {
console.log(arguments); // Has arguments object
}
const arrowFunction = () => {
console.log(arguments); // ReferenceError: arguments is not defined
};
- Constructor Usage:
function RegularConstructor() {
this.name = 'test';
}
const ArrowConstructor = () => {
this.name = 'test';
};
new RegularConstructor(); // Works
new ArrowConstructor(); // TypeError: ArrowConstructor is not a constructor
- Hoisting:
// Regular functions are hoisted
console.log(regularFunc()); // Works - 'Hello'
function regularFunc() {
return 'Hello';
}
// Arrow functions are not hoisted
console.log(arrowFunc()); // ReferenceError: Cannot access 'arrowFunc' before initialization
const arrowFunc = () => 'Hello';
When to Use Each:
Use Arrow Functions When:
- Writing short, simple functions
- Working with array methods (map, filter, reduce)
- Need lexical
thisbinding - Writing functional programming style code
// Great for array methods
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
Use Regular Functions When:
- Need
thisto be dynamically bound - Need access to
argumentsobject - Creating constructors
- Need function hoisting
- Writing methods in objects/classes
// Object methods should use regular functions
const calculator = {
value: 0,
add: function(num) {
this.value += num;
return this;
},
multiply: function(num) {
this.value *= num;
return this;
}
};
Destructuring assignment allows you to extract values from arrays or properties from objects into distinct variables.
Array Destructuring:
// Basic array destructuring
const colors = ['red', 'green', 'blue'];
const [first, second, third] = colors;
console.log(first); // 'red'
console.log(second); // 'green'
console.log(third); // 'blue'
// Skip elements
const [primary, , tertiary] = colors;
console.log(primary); // 'red'
console.log(tertiary); // 'blue'
// Default values
const [a, b, c, d = 'yellow'] = colors;
console.log(d); // 'yellow'
// Rest operator
const [head, ...tail] = colors;
console.log(head); // 'red'
console.log(tail); // ['green', 'blue']
// Swap variables
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2, 1
Object Destructuring:
const user = {
id: 1,
name: 'John Doe',
email: 'john@example.com',
address: {
city: 'New York',
country: 'USA'
}
};
// Basic object destructuring
const { name, email, id } = user;
console.log(name); // 'John Doe'
// Rename variables
const { name: userName, email: userEmail } = user;
console.log(userName); // 'John Doe'
// Default values
const { name, age = 25 } = user;
console.log(age); // 25
// Nested destructuring
const { address: { city, country } } = user;
console.log(city); // 'New York'
// Rest operator
const { id, ...userInfo } = user;
console.log(userInfo); // { name: 'John Doe', email: 'john@example.com', address: {...} }
Practical Use Cases:
- Function Parameters:
// Instead of passing many parameters
function createUser(name, email, age, city, country) {
// ...
}
// Use object destructuring
function createUser({ name, email, age = 18, address: { city, country } }) {
return { name, email, age, city, country };
}
createUser({
name: 'John',
email: 'john@example.com',
address: { city: 'NYC', country: 'USA' }
});
- API Response Handling:
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
const { data: user, status, message } = await response.json();
if (status === 'success') {
const { name, email, profile: { avatar, bio } } = user;
return { name, email, avatar, bio };
}
throw new Error(message);
}
- React Props:
function UserCard({ user: { name, email, avatar }, onEdit, onDelete }) {
return (
<div>
<img src={avatar} alt={name} />
<h3>{name}</h3>
<p>{email}</p>
<button onClick={onEdit}>Edit</button>
<button onClick={onDelete}>Delete</button>
</div>
);
}
- Array Methods:
const users = [
{ id: 1, name: 'John', role: 'admin' },
{ id: 2, name: 'Jane', role: 'user' }
];
// Destructure in map
const userNames = users.map(({ name }) => name);
// Destructure in filter
const admins = users.filter(({ role }) => role === 'admin');
The spread (...) and rest (...) operators use the same syntax but serve different purposes depending on context.
Spread Operator (...):
Expands an iterable (array, string, object) into individual elements.
Array Spread:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// Combine arrays
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// Add elements
const withExtra = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// Clone array
const cloned = [...arr1]; // [1, 2, 3] - shallow copy
// Convert string to array
const chars = [...'hello']; // ['h', 'e', 'l', 'l', 'o']
// Function arguments
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6
Object Spread:
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
// Combine objects
const combined = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }
// Override properties
const updated = { ...obj1, b: 10 }; // { a: 1, b: 10 }
// Clone object
const cloned = { ...obj1 }; // { a: 1, b: 2 } - shallow copy
// Add properties
const withExtra = { ...obj1, e: 5 }; // { a: 1, b: 2, e: 5 }
Rest Operator (...):
Collects multiple elements into a single variable.
Function Parameters:
// Collect remaining arguments
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
// Mix with regular parameters
function greet(greeting, ...names) {
return `${greeting} ${names.join(', ')}!`;
}
console.log(greet('Hello', 'John', 'Jane', 'Bob')); // "Hello John, Jane, Bob!"
Array Destructuring:
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// Skip elements
const [a, , ...remaining] = [1, 2, 3, 4, 5];
console.log(a); // 1
console.log(remaining); // [3, 4, 5]
Object Destructuring:
const { name, ...otherProps } = { name: 'John', age: 30, city: 'NYC' };
console.log(name); // 'John'
console.log(otherProps); // { age: 30, city: 'NYC' }
Practical Use Cases:
- Array Manipulation:
// Remove duplicates
const unique = [...new Set([1, 2, 2, 3, 3, 4])]; // [1, 2, 3, 4]
// Insert at specific position
function insertAt(array, index, ...items) {
return [...array.slice(0, index), ...items, ...array.slice(index)];
}
const result = insertAt([1, 2, 5], 2, 3, 4); // [1, 2, 3, 4, 5]
- Object Updates:
// Immutable updates
const updateUser = (user, updates) => ({ ...user, ...updates });
const user = { name: 'John', age: 30 };
const updated = updateUser(user, { age: 31, city: 'NYC' });
// { name: 'John', age: 31, city: 'NYC' }
- React State Updates:
// Add item to array
const addItem = (items, newItem) => [...items, newItem];
// Remove item from array
const removeItem = (items, id) => items.filter(item => item.id !== id);
// Update object in array
const updateItem = (items, id, updates) =>
items.map(item => item.id === id ? { ...item, ...updates } : item);
- API Calls:
// Merge query parameters
const buildUrl = (baseUrl, ...params) => {
const queryString = params.join('&');
return `${baseUrl}?${queryString}`;
};
const url = buildUrl('/api/users', 'page=1', 'limit=10', 'sort=name');
Template literals are string literals that allow embedded expressions and multi-line strings.
Basic Template Literals:
const name = 'John';
const age = 30;
// String interpolation
const message = `Hello, my name is ${name} and I am ${age} years old.`;
// Multi-line strings
const html = `
<div class="user-card">
<h2>${name}</h2>
<p>Age: ${age}</p>
</div>
`;
// Expressions
const price = 19.99;
const total = `Total: $${(price * 1.08).toFixed(2)}`;
Tagged Template Literals:
function myTag(strings, ...values) {
return strings.reduce((result, string, i) => {
return result + string + (values[i] || '');
}, '');
}
const name = 'John';
const result = myTag`Hello ${name}, you are ${30} years old.`;
// Practical example: SQL query builder
function sql(strings, ...values) {
return strings.reduce((query, string, i) => {
const value = values[i];
const escaped = typeof value === 'string' ? `'${value.replace(/'/g, "''")}'` : value;
return query + string + (escaped || '');
}, '');
}
const userId = 123;
const query = sql`SELECT * FROM users WHERE id = ${userId}`;
ES6 modules provide a standardized way to organize and share code between files.
Export Syntax:
// Named exports
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export class Calculator { multiply(a, b) { return a * b; } }
// Default export
export default function subtract(a, b) { return a - b; }
// Mixed exports
export const VERSION = '1.0.0';
export default class MathUtils { static divide(a, b) { return a / b; } }
Import Syntax:
// Named imports
import { PI, add, Calculator } from './math.js';
// Default import
import subtract from './math.js';
// Mixed imports
import MathUtils, { VERSION } from './math.js';
// Namespace import
import * as math from './math.js';
// Dynamic import
const { add, subtract } = await import('./math.js');
CommonJS vs ES6 Modules:
// CommonJS
const fs = require('fs');
module.exports = { readFile: fs.readFile };
// ES6 Modules
import fs from 'fs';
export { readFile: fs.readFile };
Module Bundling:
// Code splitting
const Home = lazy(() => import('./components/Home'));
const About = lazy(() => import('./components/About'));
// Tree shaking (only used exports are bundled)
import { debounce } from 'lodash-es'; // Only debounce is bundled
import _ from 'lodash'; // Entire library bundled