JavaScript Objects & Arrays

Master JavaScript objects and arrays - the fundamental data structures for React development. Learn object manipulation, array methods, and destructuring patterns essential for modern React applications.

JavaScript Objects

Objects are key-value pairs that form the backbone of JavaScript. In React, they're used for props, state, and component data.

Object Creation & Manipulation

Essential object patterns for React development

// JavaScript Objects Examples

// Object literal syntax
const user = {
  id: 1,
  name: 'John Doe',
  email: 'john@example.com',
  age: 25,
  role: 'Developer',
  isActive: true
};

// Object with methods (React component pattern)
const userProfile = {
  // Properties
  firstName: 'John',
  lastName: 'Doe',
  preferences: {
    theme: 'dark',
    language: 'en',
    notifications: true
  },
  
  // Methods
  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  },
  
  updatePreference(key, value) {
    this.preferences[key] = value;
    return this.preferences;
  },
  
  // Arrow function method (lexical this)
  getDisplayInfo: () => {
    // Note: arrow functions don't bind 'this'
    return 'User profile info';
  }
};

// Object constructor function
function User(name, email, role) {
  this.name = name;
  this.email = email;
  this.role = role;
  this.createdAt = new Date();
  
  this.getInfo = function() {
    return `${this.name} (${this.role})`;
  };
}

// ES6 Class syntax (React component pattern)
class UserManager {
  constructor() {
    this.users = [];
    this.nextId = 1;
  }
  
  addUser(userData) {
    const newUser = {
      id: this.nextId++,
      ...userData,
      createdAt: new Date().toISOString()
    };
    this.users.push(newUser);
    return newUser;
  }
  
  findUser(id) {
    return this.users.find(user => user.id === id);
  }
  
  updateUser(id, updates) {
    const userIndex = this.users.findIndex(user => user.id === id);
    if (userIndex !== -1) {
      // Immutable update pattern (React state)
      this.users[userIndex] = {
        ...this.users[userIndex],
        ...updates,
        updatedAt: new Date().toISOString()
      };
      return this.users[userIndex];
    }
    return null;
  }
}

// Object property access patterns
function demonstrateObjectAccess() {
  const obj = {
    'simple-key': 'value1',
    'complex key': 'value2',
    dynamicKey: 'value3',
    nested: {
      level1: {
        level2: 'deep value'
      }
    }
  };
  
  return {
    dotNotation: obj.dynamicKey,
    bracketNotation: obj['simple-key'],
    complexKey: obj['complex key'],
    deepAccess: obj.nested.level1.level2,
    dynamicAccess: obj[`dynamic${'Key'}`]
  };
}

// Object methods and properties
function demonstrateObjectMethods() {
  const sampleObject = {
    name: 'React Component',
    type: 'functional',
    props: ['children', 'className', 'onClick']
  };
  
  return {
    keys: Object.keys(sampleObject),
    values: Object.values(sampleObject),
    entries: Object.entries(sampleObject),
    hasOwnProperty: sampleObject.hasOwnProperty('name'),
    propertyNames: Object.getOwnPropertyNames(sampleObject)
  };
}

// Immutable object updates (React pattern)
function updateObjectImmutably(originalObject, updates) {
  return {
    ...originalObject,
    ...updates,
    updatedAt: Date.now()
  };
}

// Nested object updates
function updateNestedObject(obj, path, value) {
  const keys = path.split('.');
  const result = { ...obj };
  
  let current = result;
  for (let i = 0; i < keys.length - 1; i++) {
    current[keys[i]] = { ...current[keys[i]] };
    current = current[keys[i]];
  }
  
  current[keys[keys.length - 1]] = value;
  return result;
}

// Event handlers
document.getElementById('update-profile')?.addEventListener('click', () => {
  const updatedUser = {
    name: document.getElementById('name').value,
    email: document.getElementById('email').value,
    age: parseInt(document.getElementById('age').value),
    role: document.getElementById('role').value
  };
  
  const profileHTML = `
    <div class="profile-card">
      <h4>${updatedUser.name}</h4>
      <p>Email: ${updatedUser.email}</p>
      <p>Age: ${updatedUser.age}</p>
      <p>Role: ${updatedUser.role}</p>
    </div>
  `;
  
  document.getElementById('profile-display').innerHTML = profileHTML;
});

document.getElementById('demo-methods')?.addEventListener('click', () => {
  const methods = demonstrateObjectMethods();
  const output = document.getElementById('methods-output');
  
  output.innerHTML = `
    <div>Keys: [${methods.keys.join(', ')}]</div>
    <div>Values: [${methods.values.join(', ')}]</div>
    <div>Entries: ${JSON.stringify(methods.entries)}</div>
    <div>Has 'name' property: ${methods.hasOwnProperty}</div>
  `;
});

document.getElementById('demo-nested')?.addEventListener('click', () => {
  const component = {
    name: 'UserCard',
    props: {
      user: {
        id: 1,
        profile: {
          name: 'Alice',
          avatar: 'avatar.jpg'
        }
      },
      theme: 'dark',
      onUpdate: 'function'
    }
  };
  
  const output = document.getElementById('nested-output');
  output.innerHTML = `
    <div>Component: ${component.name}</div>
    <div>User Name: ${component.props.user.profile.name}</div>
    <div>Theme: ${component.props.theme}</div>
    <pre>${JSON.stringify(component, null, 2)}</pre>
  `;
});

document.getElementById('demo-comparison')?.addEventListener('click', () => {
  const obj1 = { name: 'Alice', age: 25 };
  const obj2 = { name: 'Alice', age: 25 };
  const obj3 = obj1;
  
  const updated = updateObjectImmutably(obj1, { age: 26 });
  
  const output = document.getElementById('comparison-output');
  output.innerHTML = `
    <div>obj1 === obj2: ${obj1 === obj2} (false - different references)</div>
    <div>obj1 === obj3: ${obj1 === obj3} (true - same reference)</div>
    <div>Original obj1: ${JSON.stringify(obj1)}</div>
    <div>Updated copy: ${JSON.stringify(updated)}</div>
    <div>obj1 unchanged: ${obj1.age === 25}</div>
  `;
});

Explanation:

Objects are fundamental to React development - they represent component props, state, and data. Understanding object manipulation, property access, and immutable updates is crucial for effective React programming.

Best Practices:

  • Use descriptive property names for better code readability
  • Prefer immutable updates to avoid unintended side effects
  • Use Object.keys(), Object.values(), and Object.entries() for iteration
  • Understand the difference between shallow and deep copying

JavaScript Arrays & Essential Methods

Arrays and their methods are essential for rendering lists, filtering data, and transforming information in React applications.

Array Methods for React Development

Essential array methods: map, filter, reduce, forEach, and more

// JavaScript Array Methods Examples

// Sample data for demonstrations
const users = [
  { id: 1, name: 'Alice Johnson', role: 'Developer', age: 28, active: true },
  { id: 2, name: 'Bob Smith', role: 'Designer', age: 32, active: false },
  { id: 3, name: 'Charlie Brown', role: 'Developer', age: 25, active: true },
  { id: 4, name: 'Diana Ross', role: 'Manager', age: 35, active: true },
  { id: 5, name: 'Eve Wilson', role: 'Designer', age: 29, active: false }
];

let todos = [
  { id: 1, text: 'Learn JavaScript', completed: true },
  { id: 2, text: 'Master React', completed: false },
  { id: 3, text: 'Build awesome apps', completed: false }
];

let nextTodoId = 4;

// Array.map() - Transform data (React rendering pattern)
const transformUserData = () => {
  const transformed = users.map(user => ({
    ...user,
    displayName: user.name.toUpperCase(),
    isAdult: user.age >= 18,
    status: user.active ? 'Active' : 'Inactive'
  }));
  
  return transformed;
};

// Array.filter() - Filter data based on conditions
const filterActiveUsers = () => {
  return users.filter(user => user.active);
};

const filterByRole = (role) => {
  return users.filter(user => user.role === role);
};

// Array.reduce() - Aggregate data
const getUserStats = () => {
  return users.reduce((stats, user) => {
    // Count by role
    stats.byRole[user.role] = (stats.byRole[user.role] || 0) + 1;
    
    // Calculate average age
    stats.totalAge += user.age;
    stats.count += 1;
    stats.averageAge = stats.totalAge / stats.count;
    
    // Count active users
    if (user.active) stats.activeCount++;
    
    return stats;
  }, {
    byRole: {},
    totalAge: 0,
    count: 0,
    averageAge: 0,
    activeCount: 0
  });
};

// Array.find() and Array.findIndex()
const findUser = (id) => users.find(user => user.id === id);
const findUserIndex = (id) => users.findIndex(user => user.id === id);

// Array.some() and Array.every()
const hasActiveUsers = () => users.some(user => user.active);
const allUsersAdult = () => users.every(user => user.age >= 18);

// Array.sort() - Sorting data
const sortUsersByName = () => {
  return [...users].sort((a, b) => a.name.localeCompare(b.name));
};

const sortUsersByAge = () => {
  return [...users].sort((a, b) => b.age - a.age);
};

// Array.includes() and Array.indexOf()
const searchUsers = (searchTerm) => {
  return users.filter(user => 
    user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
    user.role.toLowerCase().includes(searchTerm.toLowerCase())
  );
};

// Immutable array operations (React state patterns)
const addTodo = (text) => {
  const newTodo = {
    id: nextTodoId++,
    text,
    completed: false
  };
  
  // Immutable add
  todos = [...todos, newTodo];
  return todos;
};

const toggleTodo = (id) => {
  // Immutable update
  todos = todos.map(todo =>
    todo.id === id ? { ...todo, completed: !todo.completed } : todo
  );
  return todos;
};

const removeTodo = (id) => {
  // Immutable remove
  todos = todos.filter(todo => todo.id !== id);
  return todos;
};

const clearCompletedTodos = () => {
  todos = todos.filter(todo => !todo.completed);
  return todos;
};

// Array grouping (useful for React data organization)
const groupUsersByRole = () => {
  return users.reduce((groups, user) => {
    const role = user.role;
    if (!groups[role]) {
      groups[role] = [];
    }
    groups[role].push(user);
    return groups;
  }, {});
};

// Render todo list (React-like pattern)
const renderTodos = () => {
  const todoList = document.getElementById('todo-list');
  const stats = document.getElementById('todo-stats');
  
  // Calculate stats
  const total = todos.length;
  const completed = todos.filter(t => t.completed).length;
  const remaining = total - completed;
  
  // Update stats
  stats.innerHTML = `
    <div>Total: ${total} | Completed: ${completed} | Remaining: ${remaining}</div>
  `;
  
  // Render todos
  todoList.innerHTML = todos
    .map(todo => `
      <li class="todo-item ${todo.completed ? 'completed' : ''}">
        <input type="checkbox" ${todo.completed ? 'checked' : ''} 
               onchange="toggleTodo(${todo.id}); renderTodos();">
        <span>${todo.text}</span>
        <button onclick="removeTodo(${todo.id}); renderTodos();">Delete</button>
      </li>
    `)
    .join('');
};

// Event handlers
document.getElementById('add-todo')?.addEventListener('click', () => {
  const input = document.getElementById('new-todo');
  const text = input.value.trim();
  if (text) {
    addTodo(text);
    input.value = '';
    renderTodos();
  }
});

document.getElementById('toggle-all')?.addEventListener('click', () => {
  const allCompleted = todos.every(todo => todo.completed);
  todos = todos.map(todo => ({ ...todo, completed: !allCompleted }));
  renderTodos();
});

document.getElementById('clear-completed')?.addEventListener('click', () => {
  clearCompletedTodos();
  renderTodos();
});

document.getElementById('demo-transform')?.addEventListener('click', () => {
  const transformed = transformUserData();
  const stats = getUserStats();
  
  document.getElementById('original-data').innerHTML = `
    <h4>Original Data:</h4>
    <pre>${JSON.stringify(users, null, 2)}</pre>
  `;
  
  document.getElementById('transformed-data').innerHTML = `
    <h4>Transformed Data:</h4>
    <pre>${JSON.stringify(transformed.slice(0, 2), null, 2)}</pre>
    <h4>User Statistics:</h4>
    <pre>${JSON.stringify(stats, null, 2)}</pre>
  `;
});

document.getElementById('search-users')?.addEventListener('click', () => {
  const searchTerm = document.getElementById('search-term').value;
  const results = searchUsers(searchTerm);
  
  document.getElementById('search-results').innerHTML = `
    <h4>Search Results for "${searchTerm}":</h4>
    <ul>
      ${results.map(user => `<li>${user.name} - ${user.role}</li>`).join('')}
    </ul>
  `;
});

document.getElementById('sort-users')?.addEventListener('click', () => {
  const sorted = sortUsersByName();
  
  document.getElementById('search-results').innerHTML = `
    <h4>Users Sorted by Name:</h4>
    <ul>
      ${sorted.map(user => `<li>${user.name} - ${user.role}</li>`).join('')}
    </ul>
  `;
});

document.getElementById('group-users')?.addEventListener('click', () => {
  const grouped = groupUsersByRole();
  
  const groupedHTML = Object.entries(grouped)
    .map(([role, roleUsers]) => `
      <div>
        <h5>${role} (${roleUsers.length}):</h5>
        <ul>
          ${roleUsers.map(user => `<li>${user.name}</li>`).join('')}
        </ul>
      </div>
    `)
    .join('');
  
  document.getElementById('search-results').innerHTML = `
    <h4>Users Grouped by Role:</h4>
    ${groupedHTML}
  `;
});

document.getElementById('demo-immutable')?.addEventListener('click', () => {
  const original = [1, 2, 3, 4, 5];
  
  // Immutable operations
  const doubled = original.map(x => x * 2);
  const evens = original.filter(x => x % 2 === 0);
  const sum = original.reduce((acc, x) => acc + x, 0);
  const withAdded = [...original, 6, 7];
  const withoutFirst = original.slice(1);
  const reversed = [...original].reverse();
  
  document.getElementById('immutable-output').innerHTML = `
    <div>Original: [${original.join(', ')}]</div>
    <div>Doubled: [${doubled.join(', ')}]</div>
    <div>Evens: [${evens.join(', ')}]</div>
    <div>Sum: ${sum}</div>
    <div>With Added: [${withAdded.join(', ')}]</div>
    <div>Without First: [${withoutFirst.join(', ')}]</div>
    <div>Reversed: [${reversed.join(', ')}]</div>
    <div>Original Unchanged: [${original.join(', ')}]</div>
  `;
});

// Initialize
window.toggleTodo = toggleTodo;
window.removeTodo = removeTodo;
document.addEventListener('DOMContentLoaded', renderTodos);

Explanation:

Array methods like map(), filter(), and reduce() are essential for React development. They enable data transformation, list rendering, and state management while maintaining immutability - a core React principle.

Best Practices:

  • Use map() to transform data for rendering React components
  • Use filter() to show/hide items based on conditions
  • Use reduce() to calculate derived state or aggregate data
  • Always return new arrays instead of mutating existing ones in React

Destructuring Assignment

Destructuring is essential for React development - it's used for extracting props, state values, and working with function parameters cleanly.

Object & Array Destructuring for React

Modern destructuring patterns essential for React development

// Destructuring Assignment Examples

// Object destructuring - React props pattern
const UserCard = ({ user, onEdit, onDelete, theme = 'light' }) => {
  // Destructuring nested object
  const { id, name, email, profile: { avatar, bio } = {} } = user;
  
  return `
    <div class="user-card ${theme}">
      <img src="${avatar || 'default-avatar.png'}" alt="${name}">
      <h3>${name}</h3>
      <p>${email}</p>
      <p>${bio || 'No bio available'}</p>
      <div class="actions">
        <button onclick="handleEdit(${id})">Edit</button>
        <button onclick="handleDelete(${id})">Delete</button>
      </div>
    </div>
  `;
};

// Array destructuring - React hooks pattern
let counterState = [0, null]; // [value, setter]

const useCounter = (initialValue = 0) => {
  let count = initialValue;
  
  const setCount = (newValue) => {
    count = typeof newValue === 'function' ? newValue(count) : newValue;
    updateCounterDisplay();
    return count;
  };
  
  counterState = [count, setCount];
  return counterState;
};

// Destructuring function parameters (React event handlers)
const handleFormSubmit = ({ target, preventDefault }) => {
  preventDefault();
  
  // Destructuring form data
  const formData = new FormData(target);
  const { name, email, role } = Object.fromEntries(formData);
  
  return { name, email, role };
};

// API response destructuring
const processApiResponse = (response) => {
  // Destructuring with renaming and defaults
  const {
    data: userData,
    status = 'unknown',
    message: apiMessage = 'No message',
    meta: { total, page = 1, limit = 10 } = {}
  } = response;
  
  return {
    userData,
    status,
    apiMessage,
    pagination: { total, page, limit }
  };
};

// Rest operator with destructuring
const extractUserInfo = (user) => {
  // Extract specific properties, rest goes to 'others'
  const { id, name, email, ...others } = user;
  
  return {
    essential: { id, name, email },
    additional: others
  };
};

// Array destructuring with rest
const processUserList = (users) => {
  // Get first user, second user, and rest
  const [firstUser, secondUser, ...remainingUsers] = users;
  
  return {
    primary: firstUser,
    secondary: secondUser,
    others: remainingUsers
  };
};

// Nested destructuring (React component props)
const ProfileComponent = ({
  user: {
    personal: { firstName, lastName },
    contact: { email, phone },
    settings: { theme = 'light', language = 'en' } = {}
  },
  onUpdate,
  isEditable = false
}) => {
  const fullName = `${firstName} ${lastName}`;
  
  return `
    <div class="profile ${theme}">
      <h2>${fullName}</h2>
      <p>Email: ${email}</p>
      <p>Phone: ${phone || 'Not provided'}</p>
      <p>Language: ${language}</p>
      ${isEditable ? '<button onclick="editProfile()">Edit</button>' : ''}
    </div>
  `;
};

// Swap variables with destructuring
const swapValues = (a, b) => {
  [a, b] = [b, a];
  return { a, b };
};

// Function returning multiple values
const getWindowDimensions = () => {
  const { innerWidth: width, innerHeight: height } = window;
  return { width, height };
};

// Destructuring in for loops
const processUsers = (users) => {
  const results = [];
  
  for (const { id, name, active } of users) {
    if (active) {
      results.push(`Active user: ${name} (ID: ${id})`);
    }
  }
  
  return results;
};

// Sample data
const sampleUsers = [
  {
    id: 1,
    name: 'Alice Johnson',
    email: 'alice@example.com',
    profile: {
      avatar: 'alice.jpg',
      bio: 'Full-stack developer'
    }
  },
  {
    id: 2,
    name: 'Bob Smith',
    email: 'bob@example.com',
    profile: {
      avatar: 'bob.jpg',
      bio: 'UI/UX Designer'
    }
  }
];

const sampleApiResponse = {
  data: [
    { id: 1, name: 'User 1', role: 'admin' },
    { id: 2, name: 'User 2', role: 'user' }
  ],
  status: 'success',
  message: 'Users fetched successfully',
  meta: {
    total: 50,
    page: 1,
    limit: 10
  }
};

// Helper functions
const updateCounterDisplay = () => {
  document.getElementById('counter-display').textContent = counterState[0];
  document.getElementById('state-info').innerHTML = `
    <div>Current state: [${counterState[0]}, function]</div>
    <div>Destructured as: const [count, setCount] = useState(${counterState[0]})</div>
  `;
};

// Event handlers
document.getElementById('render-users')?.addEventListener('click', () => {
  const userCardsHTML = sampleUsers
    .map(user => UserCard({ 
      user, 
      onEdit: () => {}, 
      onDelete: () => {}, 
      theme: 'light' 
    }))
    .join('');
    
  document.getElementById('user-cards').innerHTML = userCardsHTML;
});

document.getElementById('increment-counter')?.addEventListener('click', () => {
  const [count, setCount] = useCounter();
  setCount(count + 1);
});

document.getElementById('reset-counter')?.addEventListener('click', () => {
  const [, setCount] = useCounter();
  setCount(0);
});

document.getElementById('fetch-user-data')?.addEventListener('click', () => {
  // Simulate API call
  const processed = processApiResponse(sampleApiResponse);
  
  document.getElementById('api-results').innerHTML = `
    <h4>Destructured API Response:</h4>
    <pre>${JSON.stringify(processed, null, 2)}</pre>
  `;
});

document.getElementById('demo-params')?.addEventListener('click', () => {
  // Demonstrate parameter destructuring
  const config = {
    theme: 'dark',
    language: 'en',
    animations: true,
    notifications: {
      email: true,
      push: false
    }
  };
  
  // Function with destructured parameters
  const applySettings = ({
    theme = 'light',
    language = 'en',
    animations = false,
    notifications: { email = false, push = false } = {}
  }) => {
    return {
      appliedTheme: theme,
      appliedLanguage: language,
      animationsEnabled: animations,
      emailNotifications: email,
      pushNotifications: push
    };
  };
  
  const result = applySettings(config);
  
  document.getElementById('param-results').innerHTML = `
    <h4>Parameter Destructuring Result:</h4>
    <pre>${JSON.stringify(result, null, 2)}</pre>
  `;
});

document.getElementById('demo-advanced')?.addEventListener('click', () => {
  // Advanced destructuring patterns
  const complexObject = {
    users: [
      { id: 1, name: 'Alice', scores: [85, 90, 88] },
      { id: 2, name: 'Bob', scores: [92, 87, 91] }
    ],
    metadata: {
      total: 2,
      avgScore: 88.5,
      filters: { active: true, role: 'student' }
    }
  };
  
  // Complex destructuring
  const {
    users: [
      { name: firstName, scores: [firstScore] },
      { name: secondName, scores: [, , thirdScore] }
    ],
    metadata: {
      total,
      filters: { active }
    }
  } = complexObject;
  
  // Array destructuring with computed property
  const [first, second, third] = ['apple', 'banana', 'cherry'];
  const { length } = ['apple', 'banana', 'cherry'];
  
  document.getElementById('advanced-results').innerHTML = `
    <h4>Advanced Destructuring:</h4>
    <div>First user: ${firstName}, first score: ${firstScore}</div>
    <div>Second user: ${secondName}, third score: ${thirdScore}</div>
    <div>Total users: ${total}, Active filter: ${active}</div>
    <div>Array destructuring: ${first}, ${second}, ${third}</div>
    <div>Array length: ${length}</div>
  `;
});

// Initialize counter
document.addEventListener('DOMContentLoaded', () => {
  useCounter(0);
  updateCounterDisplay();
});

Explanation:

Destructuring assignment provides a clean way to extract values from objects and arrays. It's extensively used in React for props, state, and function parameters, making code more readable and maintainable.

Best Practices:

  • Use destructuring to extract React props for cleaner component code
  • Provide default values in destructuring for optional props
  • Use array destructuring with React hooks (useState, useEffect)
  • Combine destructuring with rest operators for flexible function parameters

Objects & Arrays Best Practices for React

📦 Object Management

  • • Use object destructuring for React props and state
  • • Prefer immutable updates with spread operator (...)
  • • Use descriptive property names for better readability
  • • Leverage Object.keys(), Object.values(), Object.entries()
  • • Understand reference vs. value equality for objects

📋 Array Operations

  • • Use map() for transforming data and rendering lists
  • • Use filter() for conditional rendering and data filtering
  • • Use reduce() for aggregating data and complex transformations
  • • Always return new arrays instead of mutating existing ones
  • • Combine array methods for powerful data processing pipelines