Learn to extract values from arrays and objects using destructuring assignment for cleaner, more readable code.
Destructuring assignment is one of ES6's most elegant features, allowing you to extract values from arrays and objects using a syntax that mirrors their construction. This powerful feature eliminates verbose property access and array indexing, replacing it with clean, declarative code that clearly expresses your intent.
Beyond simple extraction, destructuring supports default values, variable renaming, nested structures, and rest patterns. It's essential for modern JavaScript development, especially in frameworks like React where props destructuring and state management rely heavily on these patterns.
In this comprehensive lesson, you'll master all aspects of destructuring assignment, from basic extraction to advanced patterns, making your JavaScript code more expressive and maintainable.
Array destructuring allows you to extract elements from arrays using position-based syntax. This creates cleaner, more readable code compared to traditional index-based access.
1. Basic Array Destructuring
1// Traditional array access
2const colors = ['red', 'green', 'blue', 'yellow'];
3const firstColor = colors[0];
4const secondColor = colors[1];
5const thirdColor = colors[2];
6
7// Array destructuring - much cleaner
8const [first, second, third] = colors;
9console.log(first); // 'red'
10console.log(second); // 'green'
11console.log(third); // 'blue'
12
13// Extracting specific elements
14const [primary, , tertiary] = colors; // Skip second element
15console.log(primary); // 'red'
16console.log(tertiary); // 'blue'2. Default Values in Array Destructuring
1// Handle undefined values with defaults
2const [a = 1, b = 2, c = 3] = [10];
3console.log(a, b, c); // 10 2 3
4
5// Practical example with function returns
6function getCoordinates() {
7 return [100, 200]; // Sometimes might return fewer values
8}
9
10const [x = 0, y = 0, z = 0] = getCoordinates();
11console.log(`Position: (${x}, ${y}, ${z})`); // Position: (100, 200, 0)
12
13// Dynamic default values
14const [width = window.innerWidth, height = window.innerHeight] = [];
15console.log(`Dimensions: ${width}x${height}`);3. Rest Pattern in Array Destructuring
1// Extract first few elements, capture rest
2const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
3const [first, second, ...remaining] = numbers;
4
5console.log(first); // 1
6console.log(second); // 2
7console.log(remaining); // [3, 4, 5, 6, 7, 8, 9, 10]
8
9// Practical example: processing arrays
10const [head, ...tail] = ['apple', 'banana', 'cherry', 'date'];
11console.log(`First fruit: ${head}`);
12console.log(`Other fruits: ${tail.join(', ')}`);
13
14// Split array processing
15const data = [1, 2, 3, 4, 5, 6];
16const [sum, product, ...others] = data.reduce(
17 ([s, p, ...rest], num, i) => {
18 if (i < 2) return [s + num, p * num, ...rest];
19 return [s, p, ...rest, num];
20 },
21 [0, 1]
22);4. Array Destructuring in Practical Scenarios
1// Swapping variables (no temporary variable needed!)
2let a = 10, b = 20;
3[a, b] = [b, a];
4console.log(a, b); // 20 10
5
6// Multiple return values from functions
7function getMinMax(numbers) {
8 return [Math.min(...numbers), Math.max(...numbers)];
9}
10const [min, max] = getMinMax([3, 7, 1, 9, 2]);
11console.log(`Range: ${min} to ${max}`); // Range: 1 to 9
12
13// Working with split strings
14const fullName = 'John Michael Doe';
15const [firstName, middleName, lastName] = fullName.split(' ');
16console.log(`First: ${firstName}, Last: ${lastName}`);
17
18// Regular expression matches
19const url = 'https://example.com:8080/path';
20const [, protocol, domain, port, path] = url.match(/^(https?):\/\/([^:]+):(\d+)(\/.*)$/);
21console.log({ protocol, domain, port, path });Array Destructuring Best Practices:
Object destructuring extracts properties using their names, providing more flexibility than array destructuring. It's perfect for working with configuration objects, API responses, and function parameters.
1. Basic Object Destructuring
1// Traditional property access
2const user = {
3 name: 'Alice Johnson',
4 email: '[email protected]',
5 age: 28,
6 city: 'New York'
7};
8
9const name = user.name;
10const email = user.email;
11const age = user.age;
12
13// Object destructuring - cleaner and more declarative
14const { name, email, age } = user;
15console.log(`${name} (${email}) is ${age} years old`);
16
17// Extracting specific properties
18const { name: userName, city } = user;
19console.log(`User ${userName} lives in ${city}`);2. Variable Renaming and Default Values
1const apiResponse = {
2 user_name: 'john_doe',
3 user_email: '[email protected]',
4 is_active: true
5 // Note: user_role is missing
6};
7
8// Rename variables to camelCase and provide defaults
9const {
10 user_name: username,
11 user_email: email,
12 user_role: role = 'user',
13 is_active: isActive = false,
14 last_login: lastLogin = 'Never'
15} = apiResponse;
16
17console.log(`Username: ${username}`);
18console.log(`Role: ${role}`); // 'user' (default)
19console.log(`Last login: ${lastLogin}`); // 'Never' (default)
20
21// Computed property names
22const field = 'email';
23const { [field]: userEmail } = user;
24console.log(`Dynamic field ${field}: ${userEmail}`);3. Nested Object Destructuring
1const employee = {
2 name: 'Sarah Williams',
3 position: 'Software Engineer',
4 contact: {
5 email: '[email protected]',
6 phone: '+1-555-0123',
7 address: {
8 street: '123 Main St',
9 city: 'San Francisco',
10 state: 'CA',
11 zip: '94102'
12 }
13 },
14 skills: ['JavaScript', 'React', 'Node.js'],
15 projects: [
16 { name: 'E-commerce Platform', status: 'completed' },
17 { name: 'Mobile App', status: 'in-progress' }
18 ]
19};
20
21// Extract nested properties
22const {
23 name,
24 contact: {
25 email,
26 address: {
27 city,
28 state
29 }
30 },
31 skills: [primarySkill, secondarySkill],
32 projects: [firstProject]
33} = employee;
34
35console.log(`${name} from ${city}, ${state}`);
36console.log(`Email: ${email}`);
37console.log(`Primary skill: ${primarySkill}`);
38console.log(`First project: ${firstProject.name} (${firstProject.status})`);
39
40// Nested destructuring with defaults
41const {
42 department = 'Engineering',
43 contact: {
44 slack: slackId = 'Not provided',
45 address: {
46 country = 'USA'
47 } = {}
48 } = {}
49} = employee;
50
51console.log(`Department: ${department}`);
52console.log(`Country: ${country}`);4. Rest Pattern in Object Destructuring
1const settings = {
2 theme: 'dark',
3 language: 'en',
4 notifications: true,
5 autoSave: true,
6 debugMode: false,
7 apiUrl: 'https://api.example.com',
8 version: '1.2.0'
9};
10
11// Extract specific properties, collect others
12const { theme, language, ...otherSettings } = settings;
13console.log('UI Settings:', { theme, language });
14console.log('Other settings:', otherSettings);
15
16// Practical example: filtering object properties
17function sanitizeUserData(userData) {
18 const { password, internalId, ...safeData } = userData;
19 return safeData; // Return user data without sensitive fields
20}
21
22const rawUser = {
23 id: 123,
24 name: 'Alice',
25 email: '[email protected]',
26 password: 'secret123',
27 internalId: 'INTERNAL_456'
28};
29
30const cleanUser = sanitizeUserData(rawUser);
31console.log(cleanUser); // { id: 123, name: 'Alice', email: '[email protected]' }5. Real-World Object Destructuring Patterns
1// Configuration objects with destructuring
2function createServer({
3 port = 3000,
4 host = 'localhost',
5 cors = true,
6 compression = true,
7 middleware = [],
8 ...options
9} = {}) {
10 console.log(`Starting server on ${host}:${port}`);
11 console.log(`CORS: ${cors ? 'enabled' : 'disabled'}`);
12 console.log(`Additional options:, options`);
13
14 return {
15 start: () => console.log('Server started'),
16 stop: () => console.log('Server stopped')
17 };
18}
19
20// Usage with partial configuration
21const server = createServer({
22 port: 8080,
23 middleware: ['logger', 'auth'],
24 rateLimit: true
25});
26
27// API response handling
28async function fetchUserProfile(userId) {
29 const response = await fetch(`/api/users/${userId}`);
30 const {
31 data: {
32 user: {
33 name,
34 avatar,
35 stats: { posts, followers } = { posts: 0, followers: 0 }
36 } = {}
37 } = {},
38 meta: { timestamp } = {}
39 } = await response.json();
40
41 return { name, avatar, posts, followers, timestamp };
42}
43
44// State management patterns (Redux-style)
45function userReducer(state, action) {
46 const { type, payload } = action;
47
48 switch (type) {
49 case 'UPDATE_PROFILE': {
50 const { name, email, ...otherUpdates } = payload;
51 return {
52 ...state,
53 profile: {
54 ...state.profile,
55 name,
56 email,
57 ...otherUpdates
58 }
59 };
60 }
61 case 'SET_PREFERENCES': {
62 const { theme, notifications, ...otherPrefs } = payload;
63 return {
64 ...state,
65 preferences: { theme, notifications, ...otherPrefs }
66 };
67 }
68 default:
69 return state;
70 }
71}Object Destructuring Best Practices:
Function parameter destructuring is one of the most powerful applications of destructuring, enabling clean API design and flexible function signatures.
1. Object Parameter Destructuring
1// Traditional approach (order-dependent, hard to remember)
2function createUser(name, email, age, isActive, role) {
3 return { name, email, age, isActive, role };
4}
5
6// Hard to remember parameter order
7const user1 = createUser('John', '[email protected]', 25, true, 'admin');
8
9// ES6 destructured parameters (order-independent, self-documenting)
10function createUserES6({ name, email, age, isActive = true, role = 'user' }) {
11 // Parameters are self-documenting
12 console.log(`Creating ${role}: ${name} (${email}), age ${age}, active: ${isActive}`);
13
14 return { name, email, age, isActive, role };
15}
16
17// Much clearer usage - order doesn't matter!
18const user2 = createUserES6({
19 email: '[email protected]',
20 name: 'Jane Smith',
21 age: 30,
22 role: 'moderator'
23 // isActive will default to true
24});
25
26// Can omit optional parameters entirely
27const user3 = createUserES6({
28 name: 'Bob Wilson',
29 email: '[email protected]',
30 age: 35
31});2. Array Parameter Destructuring
1// Working with coordinate systems
2function drawLine([x1, y1], [x2, y2], { color = 'black', width = 1 } = {}) {
3 console.log(`Drawing line from (${x1},${y1}) to (${x2},${y2})`);
4 console.log(`Style: ${color}, width: ${width}px`);
5
6 // Actual drawing logic would go here
7 return { startPoint: [x1, y1], endPoint: [x2, y2], style: { color, width } };
8}
9
10// Clean function calls
11drawLine([0, 0], [100, 100], { color: 'red', width: 3 });
12drawLine([50, 25], [200, 150]); // Uses default style
13
14// Matrix operations
15function addMatrices([[a, b], [c, d]], [[e, f], [g, h]]) {
16 return [
17 [a + e, b + f],
18 [c + g, d + h]
19 ];
20}
21
22const matrix1 = [[1, 2], [3, 4]];
23const matrix2 = [[5, 6], [7, 8]];
24const result = addMatrices(matrix1, matrix2);
25console.log(result); // [[6, 8], [10, 12]]3. Mixed Destructuring Patterns
1// Complex API endpoint handler
2function handleUserRequest(
3 { userId, action, metadata = {} }, // Request object
4 [timestamp, requestId], // Array parameters
5 {
6 authenticate = true,
7 logRequest = true,
8 ...options
9 } = {} // Configuration with rest
10) {
11 if (logRequest) {
12 console.log(`[${timestamp}] Request ${requestId}: ${action} for user ${userId}`);
13 }
14
15 if (authenticate) {
16 console.log('Authenticating user...');
17 }
18
19 console.log('Metadata:', metadata);
20 console.log('Additional options:', options);
21
22 // Process request logic here
23 return { success: true, userId, action, requestId };
24}
25
26// Usage
27handleUserRequest(
28 { userId: 123, action: 'updateProfile', metadata: { source: 'mobile' } },
29 [Date.now(), 'req-456'],
30 { authenticate: true, rateLimit: 100 }
31);
32
33// Event handler with destructuring
34function handleFormSubmit({
35 target: {
36 elements: {
37 username: { value: username },
38 email: { value: email },
39 password: { value: password }
40 }
41 },
42 preventDefault
43}) {
44 preventDefault();
45
46 console.log('Form data:', { username, email });
47 // Don't log password!
48
49 // Process form submission
50 return submitUserData({ username, email, password });
51}4. Advanced Parameter Destructuring Patterns
1// React component-style props destructuring
2function UserCard({
3 user: {
4 name,
5 avatar,
6 email,
7 stats: { posts = 0, followers = 0 } = {}
8 },
9 showEmail = true,
10 theme = 'light',
11 onClick = () => {},
12 ...cardProps
13}) {
14 return {
15 type: 'UserCard',
16 props: {
17 name,
18 avatar,
19 ...(showEmail && { email }),
20 stats: { posts, followers },
21 theme,
22 onClick,
23 ...cardProps
24 }
25 };
26}
27
28// Usage
29const card = UserCard({
30 user: {
31 name: 'Alice Johnson',
32 avatar: '/avatars/alice.jpg',
33 email: '[email protected]',
34 stats: { posts: 42, followers: 156 }
35 },
36 showEmail: false,
37 className: 'user-card--featured',
38 'data-testid': 'user-card-alice'
39});
40
41// Configuration builder pattern
42function createDatabaseConnection({
43 // Connection details
44 host = 'localhost',
45 port = 5432,
46 database,
47 username,
48 password,
49
50 // Pool configuration
51 pool: {
52 min = 2,
53 max = 10,
54 acquireTimeoutMillis = 60000,
55 ...poolOptions
56 } = {},
57
58 // Additional options
59 ssl = false,
60 timeout = 30000,
61 ...connectionOptions
62}) {
63 if (!database || !username || !password) {
64 throw new Error('Database, username, and password are required');
65 }
66
67 const config = {
68 host,
69 port,
70 database,
71 user: username,
72 password,
73 ssl,
74 connectionTimeoutMillis: timeout,
75 pool: {
76 min,
77 max,
78 acquireTimeoutMillis,
79 ...poolOptions
80 },
81 ...connectionOptions
82 };
83
84 console.log('Connecting to database with config:', {
85 ...config,
86 password: '***' // Don't log password
87 });
88
89 return config;
90}
91
92// Clean configuration
93const dbConfig = createDatabaseConnection({
94 database: 'myapp',
95 username: 'dbuser',
96 password: 'secret',
97 pool: {
98 max: 20,
99 idleTimeoutMillis: 30000
100 },
101 logging: true
102});Function Parameter Destructuring Best Practices:
Advanced destructuring patterns combine multiple techniques to handle complex data structures and create elegant solutions for common programming challenges.
1. Dynamic Property Destructuring
1// Dynamic property access with destructuring
2function getNestedProperty(obj, path) {
3 return path.split('.').reduce((current, key) => {
4 const { [key]: value } = current || {};
5 return value;
6 }, obj);
7}
8
9const data = {
10 user: {
11 profile: {
12 personal: {
13 name: 'John Doe'
14 }
15 }
16 }
17};
18
19const name = getNestedProperty(data, 'user.profile.personal.name');
20console.log(name); // 'John Doe'
21
22// Computed property names in destructuring
23function extractFields(obj, fields) {
24 return fields.reduce((result, field) => {
25 const { [field]: value = null } = obj;
26 return { ...result, [field]: value };
27 }, {});
28}
29
30const userObj = { name: 'Alice', age: 30, city: 'NYC', country: 'USA' };
31const extracted = extractFields(userObj, ['name', 'city', 'email']);
32console.log(extracted); // { name: 'Alice', city: 'NYC', email: null }2. Destructuring in Iteration Patterns
1// Object entries with destructuring
2const scores = {
3 math: 95,
4 science: 87,
5 history: 92,
6 literature: 89
7};
8
9// Traditional approach
10for (const entry of Object.entries(scores)) {
11 const subject = entry[0];
12 const score = entry[1];
13 console.log(`${subject}: ${score}`);
14}
15
16// Destructured approach - much cleaner
17for (const [subject, score] of Object.entries(scores)) {
18 console.log(`${subject}: ${score}`);
19}
20
21// Complex iteration with destructuring
22const students = [
23 { name: 'Alice', grades: { math: 95, science: 87 }, active: true },
24 { name: 'Bob', grades: { math: 82, science: 94 }, active: false },
25 { name: 'Charlie', grades: { math: 78, science: 85 }, active: true }
26];
27
28// Calculate average grades for active students
29const activeAverages = students
30 .filter(({ active }) => active)
31 .map(({ name, grades: { math, science } }) => ({
32 name,
33 average: (math + science) / 2
34 }));
35
36console.log(activeAverages);
37// [{ name: 'Alice', average: 91 }, { name: 'Charlie', average: 81.5 }]
38
39// Map with destructuring
40const userMap = new Map([
41 ['user1', { name: 'John', role: 'admin' }],
42 ['user2', { name: 'Jane', role: 'user' }],
43 ['user3', { name: 'Bob', role: 'moderator' }]
44]);
45
46for (const [userId, { name, role }] of userMap) {
47 console.log(`${userId}: ${name} (${role})`);
48}3. Destructuring with Promises and Async/Await
1// Multiple async operations with destructuring
2async function loadUserDashboard(userId) {
3 try {
4 // Parallel API calls
5 const [
6 { data: userProfile },
7 { data: userPosts },
8 { data: userStats }
9 ] = await Promise.all([
10 fetch(`/api/users/${userId}`).then(r => r.json()),
11 fetch(`/api/users/${userId}/posts`).then(r => r.json()),
12 fetch(`/api/users/${userId}/stats`).then(r => r.json())
13 ]);
14
15 // Destructure nested response data
16 const {
17 name,
18 email,
19 avatar,
20 preferences: { theme = 'light', language = 'en' } = {}
21 } = userProfile;
22
23 const {
24 posts = [],
25 totalPosts = 0
26 } = userPosts;
27
28 const {
29 followers = 0,
30 following = 0,
31 likes = 0
32 } = userStats;
33
34 return {
35 user: { name, email, avatar, theme, language },
36 content: { posts: posts.slice(0, 5), totalPosts },
37 social: { followers, following, likes }
38 };
39 } catch (error) {
40 console.error('Failed to load dashboard:', error);
41 return null;
42 }
43}
44
45// Error handling with destructuring
46async function apiRequest(endpoint, options = {}) {
47 try {
48 const response = await fetch(endpoint, options);
49 const { ok, status, statusText } = response;
50
51 if (!ok) {
52 throw new Error(`HTTP ${status}: ${statusText}`);
53 }
54
55 const data = await response.json();
56 return { success: true, data };
57 } catch (error) {
58 const { message, name } = error;
59 return { success: false, error: { message, name } };
60 }
61}
62
63// Usage
64const { success, data, error } = await apiRequest('/api/data');
65if (success) {
66 const { items = [], total = 0 } = data;
67 console.log(`Loaded ${items.length} of ${total} items`);
68} else {
69 const { message } = error;
70 console.error('API Error:', message);
71}4. React/Framework Patterns with Destructuring
1// React Hook patterns
2function useUserData(userId) {
3 const [state, setState] = useState({
4 user: null,
5 loading: true,
6 error: null
7 });
8
9 useEffect(() => {
10 async function loadUser() {
11 try {
12 const { data: user } = await fetchUser(userId);
13 setState({ user, loading: false, error: null });
14 } catch (error) {
15 setState({ user: null, loading: false, error });
16 }
17 }
18
19 loadUser();
20 }, [userId]);
21
22 // Return destructured state for clean usage
23 const { user, loading, error } = state;
24 return { user, loading, error };
25}
26
27// Component with complex props destructuring
28function UserProfileCard({
29 user: {
30 name,
31 avatar,
32 bio,
33 social: {
34 twitter,
35 github,
36 linkedin
37 } = {},
38 stats: {
39 posts = 0,
40 followers = 0,
41 following = 0
42 } = {}
43 },
44 showBio = true,
45 showSocial = true,
46 onFollow,
47 onMessage,
48 className = '',
49 ...props
50}) {
51 // Component logic using destructured props
52 const socialLinks = { twitter, github, linkedin };
53 const hasAnySocial = Object.values(socialLinks).some(Boolean);
54
55 return (
56 <div className={`user-card ${className}`} {...props}>
57 <img src={avatar} alt={name} />
58 <h3>{name}</h3>
59 {showBio && bio && <p>{bio}</p>}
60
61 <div className="stats">
62 <span>{posts} posts</span>
63 <span>{followers} followers</span>
64 <span>{following} following</span>
65 </div>
66
67 {showSocial && hasAnySocial && (
68 <div className="social">
69 {twitter && <a href={`https://twitter.com/${twitter}`}>Twitter</a>}
70 {github && <a href={`https://github.com/${github}`}>GitHub</a>}
71 {linkedin && <a href={`https://linkedin.com/in/${linkedin}`}>LinkedIn</a>}
72 </div>
73 )}
74
75 <div className="actions">
76 <button onClick={onFollow}>Follow</button>
77 <button onClick={onMessage}>Message</button>
78 </div>
79 </div>
80 );
81}
82
83// Redux/State management patterns
84function todosReducer(state = { items: [], filter: 'all' }, action) {
85 const { type, payload } = action;
86
87 switch (type) {
88 case 'ADD_TODO': {
89 const { text, id = Date.now() } = payload;
90 return {
91 ...state,
92 items: [...state.items, { id, text, completed: false }]
93 };
94 }
95
96 case 'TOGGLE_TODO': {
97 const { id } = payload;
98 return {
99 ...state,
100 items: state.items.map(todo =>
101 todo.id === id ? { ...todo, completed: !todo.completed } : todo
102 )
103 };
104 }
105
106 case 'UPDATE_FILTER': {
107 const { filter } = payload;
108 return { ...state, filter };
109 }
110
111 default:
112 return state;
113 }
114}5. Performance Considerations and Best Practices
1// Avoid deep destructuring in hot paths
2function processLargeDataset(data) {
3 // DON'T: Destructure in tight loops
4 // data.forEach(({ deeply: { nested: { value } } }) => {
5 // // Process value - destructuring overhead multiplied
6 // });
7
8 // DO: Destructure once, reuse
9 return data.map(item => {
10 const { deeply: { nested: { value } = {} } = {} } = item;
11 return processValue(value);
12 });
13}
14
15// Memory-efficient destructuring
16function createOptimizedHandler({
17 onSuccess,
18 onError,
19 retries = 3,
20 timeout = 5000
21}) {
22 // Destructure once, create closure
23 return async function handler(data) {
24 for (let attempt = 1; attempt <= retries; attempt++) {
25 try {
26 const result = await processWithTimeout(data, timeout);
27 onSuccess(result);
28 return result;
29 } catch (error) {
30 if (attempt === retries) {
31 onError(error);
32 throw error;
33 }
34 await delay(1000 * attempt); // Exponential backoff
35 }
36 }
37 };
38}
39
40// Type-safe destructuring patterns (with TypeScript)
41interface UserConfig {
42 name: string;
43 email: string;
44 preferences?: {
45 theme?: 'light' | 'dark';
46 notifications?: boolean;
47 };
48}
49
50function setupUser({
51 name,
52 email,
53 preferences: {
54 theme = 'light',
55 notifications = true
56 } = {}
57}: UserConfig) {
58 // TypeScript ensures type safety with destructuring
59 return { name, email, theme, notifications };
60}Advanced Destructuring Best Practices:
Create a comprehensive data processing system using all destructuring patterns for handling complex API responses, configuration, and data transformation.
1// Modern Data Processing Pipeline with Destructuring
2class DataProcessor {
3 constructor({
4 apiEndpoints: {
5 users = '/api/users',
6 posts = '/api/posts',
7 analytics = '/api/analytics'
8 } = {},
9 processing: {
10 batchSize = 100,
11 parallelLimit = 3,
12 retryAttempts = 3
13 } = {},
14 output: {
15 format = 'json',
16 includeMetadata = true,
17 compression = false
18 } = {},
19 ...globalOptions
20 } = {}) {
21 // Destructure and store configuration
22 Object.assign(this, {
23 endpoints: { users, posts, analytics },
24 processing: { batchSize, parallelLimit, retryAttempts },
25 output: { format, includeMetadata, compression },
26 ...globalOptions
27 });
28
29 this.cache = new Map();
30 this.metrics = { processed: 0, errors: 0, cached: 0 };
31 }
32
33 // Process user data with nested destructuring
34 async processUserData(userData) {
35 const results = [];
36
37 for (const user of userData) {
38 try {
39 // Complex nested destructuring
40 const {
41 id,
42 profile: {
43 name,
44 email,
45 avatar = '/default-avatar.png',
46 social: {
47 twitter = null,
48 github = null,
49 linkedin = null
50 } = {},
51 preferences: {
52 theme = 'light',
53 notifications = true,
54 language = 'en'
55 } = {}
56 } = {},
57 activity: {
58 lastLogin,
59 postsCount = 0,
60 commentsCount = 0,
61 likesReceived = 0
62 } = {},
63 metadata: {
64 joinDate,
65 verified = false,
66 ...otherMetadata
67 } = {}
68 } = user;
69
70 // Calculate engagement score
71 const engagementScore = this.calculateEngagement({
72 posts: postsCount,
73 comments: commentsCount,
74 likes: likesReceived
75 });
76
77 // Process social links
78 const socialLinks = this.processSocialLinks({
79 twitter,
80 github,
81 linkedin
82 });
83
84 // Create processed user object
85 const processedUser = {
86 id,
87 name,
88 email,
89 avatar,
90 preferences: { theme, notifications, language },
91 activity: {
92 lastLogin,
93 stats: { postsCount, commentsCount, likesReceived },
94 engagementScore
95 },
96 social: socialLinks,
97 metadata: {
98 joinDate,
99 verified,
100 ...otherMetadata
101 }
102 };
103
104 results.push(processedUser);
105 this.metrics.processed++;
106
107 } catch (error) {
108 console.error(`Error processing user ${user?.id || 'unknown'}:, error`);
109 this.metrics.errors++;
110 }
111 }
112
113 return results;
114 }
115
116 // Calculate engagement with parameter destructuring
117 calculateEngagement({ posts, comments, likes, weightPost = 3, weightComment = 2, weightLike = 1 }) {
118 return (posts * weightPost) + (comments * weightComment) + (likes * weightLike);
119 }
120
121 // Process social links with rest pattern
122 processSocialLinks({ twitter, github, linkedin, ...otherSocial }) {
123 const links = [];
124
125 if (twitter) links.push({ platform: 'twitter', url: `https://twitter.com/${twitter}`, handle: twitter });
126 if (github) links.push({ platform: 'github', url: `https://github.com/${github}`, handle: github });
127 if (linkedin) links.push({ platform: 'linkedin', url: `https://linkedin.com/in/${linkedin}`, handle: linkedin });
128
129 // Handle additional social platforms
130 for (const [platform, handle] of Object.entries(otherSocial)) {
131 if (handle) {
132 links.push({ platform, handle, url: `https://${platform}.com/${handle}` });
133 }
134 }
135
136 return links;
137 }
138
139 // Batch processing with array destructuring
140 async processBatches(data) {
141 const batches = this.createBatches(data, this.processing.batchSize);
142 const results = [];
143
144 for (const [batchIndex, batch] of batches.entries()) {
145 console.log(`Processing batch ${batchIndex + 1}/${batches.length}`);
146
147 try {
148 // Parallel processing within batch
149 const batchResults = await Promise.allSettled(
150 batch.map(async (item, index) => {
151 const [processed] = await Promise.all([
152 this.processUserData([item]),
153 this.delay(index * 10) // Stagger requests
154 ]);
155 return processed[0];
156 })
157 );
158
159 // Extract successful results
160 const successful = batchResults
161 .filter(({ status }) => status === 'fulfilled')
162 .map(({ value }) => value);
163
164 const failed = batchResults
165 .filter(({ status }) => status === 'rejected')
166 .map(({ reason }) => reason);
167
168 results.push(...successful);
169
170 if (failed.length > 0) {
171 console.warn(`Batch ${batchIndex + 1}: ${failed.length} items failed`);
172 }
173
174 } catch (error) {
175 console.error(`Batch ${batchIndex + 1} failed:, error`);
176 }
177 }
178
179 return results;
180 }
181
182 // Advanced API response handling
183 async fetchAndProcess(endpoint, {
184 page = 1,
185 limit = 50,
186 filters = {},
187 sort = 'id',
188 ...queryParams
189 } = {}) {
190 const cacheKey = `${endpoint}-${JSON.stringify({ page, limit, filters, sort })}`;
191
192 // Check cache first
193 if (this.cache.has(cacheKey)) {
194 this.metrics.cached++;
195 const { data } = this.cache.get(cacheKey);
196 return data;
197 }
198
199 try {
200 const url = new URL(endpoint, 'https://api.example.com');
201
202 // Build query parameters
203 Object.entries({ page, limit, sort, ...filters, ...queryParams })
204 .forEach(([key, value]) => {
205 if (value !== null && value !== undefined) {
206 url.searchParams.set(key, value);
207 }
208 });
209
210 const response = await fetch(url.toString());
211 const {
212 data = [],
213 pagination: {
214 currentPage,
215 totalPages,
216 totalItems,
217 hasNext,
218 hasPrev
219 } = {},
220 metadata: {
221 timestamp,
222 version,
223 ...responseMeta
224 } = {}
225 } = await response.json();
226
227 // Process the data
228 const processedData = await this.processUserData(data);
229
230 // Prepare result with metadata
231 const result = {
232 data: processedData,
233 pagination: { currentPage, totalPages, totalItems, hasNext, hasPrev },
234 metadata: { timestamp, version, ...responseMeta },
235 metrics: { ...this.metrics }
236 };
237
238 // Cache the result
239 this.cache.set(cacheKey, result);
240
241 return result;
242
243 } catch (error) {
244 console.error('API request failed:', error);
245 throw error;
246 }
247 }
248
249 // Export processed data with format options
250 async exportData(data, {
251 format = this.output.format,
252 filename = 'export',
253 includeMetadata = this.output.includeMetadata,
254 compression = this.output.compression,
255 ...exportOptions
256 } = {}) {
257
258 const { data: records, pagination, metadata } = data;
259
260 // Prepare export data based on format
261 let exportData;
262
263 switch (format.toLowerCase()) {
264 case 'csv': {
265 // Flatten data for CSV with destructuring
266 const flatRecords = records.map(({
267 id,
268 name,
269 email,
270 preferences: { theme, notifications, language },
271 activity: { stats: { postsCount, commentsCount, likesReceived }, engagementScore },
272 social
273 }) => ({
274 id,
275 name,
276 email,
277 theme,
278 notifications,
279 language,
280 posts: postsCount,
281 comments: commentsCount,
282 likes: likesReceived,
283 engagement: engagementScore,
284 socialCount: social.length
285 }));
286
287 exportData = this.convertToCSV(flatRecords);
288 break;
289 }
290
291 case 'json':
292 default: {
293 exportData = JSON.stringify({
294 records,
295 ...(includeMetadata && { pagination, metadata }),
296 exportInfo: {
297 timestamp: new Date().toISOString(),
298 format,
299 recordCount: records.length,
300 ...exportOptions
301 }
302 }, null, 2);
303 break;
304 }
305 }
306
307 // Handle compression if requested
308 if (compression) {
309 // In a real implementation, you'd use actual compression
310 console.log('Compressing export data...');
311 }
312
313 console.log(`Export completed: ${filename}.${format}`);
314 console.log(`Records: ${records.length}`);
315 console.log(`Format: ${format.toUpperCase()}`);
316
317 return {
318 data: exportData,
319 filename: `${filename}.${format}`,
320 size: exportData.length,
321 compressed: compression
322 };
323 }
324
325 // Utility methods
326 createBatches(array, size) {
327 const batches = [];
328 for (let i = 0; i < array.length; i += size) {
329 batches.push(array.slice(i, i + size));
330 }
331 return batches;
332 }
333
334 convertToCSV(data) {
335 if (data.length === 0) return '';
336
337 const headers = Object.keys(data[0]);
338 const csvRows = [headers.join(',')];
339
340 for (const row of data) {
341 const values = headers.map(header => {
342 const value = row[header];
343 return typeof value === 'string' ? `"${value.replace(/"/g, '""')}"` : value;
344 });
345 csvRows.push(values.join(','));
346 }
347
348 return csvRows.join('\n');
349 }
350
351 delay(ms) {
352 return new Promise(resolve => setTimeout(resolve, ms));
353 }
354
355 // Get processing statistics
356 getStats() {
357 const { processed, errors, cached } = this.metrics;
358 return {
359 processed,
360 errors,
361 cached,
362 successRate: processed > 0 ? ((processed - errors) / processed * 100).toFixed(2) + '%' : '0%',
363 cacheHitRate: (processed + cached) > 0 ? (cached / (processed + cached) * 100).toFixed(2) + '%' : '0%'
364 };
365 }
366}
367
368// Usage Example
369async function demonstrateDataProcessor() {
370 // Initialize with comprehensive configuration
371 const processor = new DataProcessor({
372 apiEndpoints: {
373 users: '/api/v2/users',
374 analytics: '/api/v2/analytics'
375 },
376 processing: {
377 batchSize: 50,
378 parallelLimit: 5,
379 retryAttempts: 2
380 },
381 output: {
382 format: 'json',
383 includeMetadata: true,
384 compression: true
385 },
386 debug: true,
387 timeout: 30000
388 });
389
390 try {
391 // Sample data with complex structure
392 const sampleUsers = [
393 {
394 id: 1,
395 profile: {
396 name: 'Alice Johnson',
397 email: '[email protected]',
398 avatar: '/avatars/alice.jpg',
399 social: {
400 twitter: 'alice_codes',
401 github: 'alicej',
402 linkedin: 'alice-johnson-dev'
403 },
404 preferences: {
405 theme: 'dark',
406 notifications: true,
407 language: 'en'
408 }
409 },
410 activity: {
411 lastLogin: '2024-01-15T10:30:00Z',
412 postsCount: 45,
413 commentsCount: 123,
414 likesReceived: 567
415 },
416 metadata: {
417 joinDate: '2023-06-15T00:00:00Z',
418 verified: true,
419 tier: 'premium',
420 tags: ['developer', 'mentor']
421 }
422 },
423 {
424 id: 2,
425 profile: {
426 name: 'Bob Smith',
427 email: '[email protected]',
428 social: {
429 github: 'bobsmith',
430 instagram: 'bob_photos'
431 },
432 preferences: {
433 theme: 'light'
434 }
435 },
436 activity: {
437 lastLogin: '2024-01-10T15:45:00Z',
438 postsCount: 12,
439 commentsCount: 34
440 },
441 metadata: {
442 joinDate: '2023-12-01T00:00:00Z',
443 verified: false
444 }
445 }
446 ];
447
448 console.log('š Processing user data...');
449 const processedData = await processor.processUserData(sampleUsers);
450
451 console.log('š Processing complete!');
452 console.log('Stats:', processor.getStats());
453
454 console.log('\nš¤ Exporting data...');
455 const exportResult = await processor.exportData(
456 {
457 data: processedData,
458 pagination: { currentPage: 1, totalPages: 1, totalItems: 2 },
459 metadata: { version: '1.0', timestamp: new Date().toISOString() }
460 },
461 {
462 format: 'json',
463 filename: 'processed_users',
464 includeMetadata: true
465 }
466 );
467
468 console.log('ā
Export completed:', {
469 filename: exportResult.filename,
470 size: `${(exportResult.size / 1024).toFixed(2)} KB`,
471 compressed: exportResult.compressed
472 });
473
474 return {
475 processed: processedData,
476 export: exportResult,
477 stats: processor.getStats()
478 };
479
480 } catch (error) {
481 console.error('ā Processing failed:', error);
482 throw error;
483 }
484}
485
486// Run the demonstration
487console.log('š Starting Data Processing Pipeline Demo...');
488demonstrateDataProcessor()
489 .then(result => {
490 console.log('\nš Demo completed successfully!');
491 console.log('Final results available in console');
492 })
493 .catch(error => {
494 console.error('š„ Demo failed:', error);
495 });Excellent work mastering destructuring assignment! You've learned to elegantly extract data from complex structures. In our next lesson, we'll explore Spread & Rest Operators, where you'll learn to expand arrays and objects, collect function arguments, and create powerful functional programming patterns. These operators work beautifully with destructuring to create modern JavaScript solutions!
Your progress is saved in this browser, on this device only.