Arrays & Objects — Data Structures
Array ek thela hai, object ek dabba — dono mein data bharo aur kaam karo.
Arrays are ordered, zero-indexed, dynamic-length collections. They're the workhorse of JavaScript data handling.
const chai = ['cutting', 'kadak', 'masala', 'green'];
// Mutating methods (change original)
chai.push('lemon'); // adds to end → length 5
chai.pop(); // removes from end → 'lemon'
chai.unshift('special'); // adds to start
chai.shift(); // removes from start → 'special'
// Non-mutating methods (return new)
const firstTwo = chai.slice(0, 2); // ['cutting', 'kadak']
console.log(chai); // original unchanged
// Searching
console.log(chai.includes('masala')); // true
console.log(chai.indexOf('green')); // 3
console.log(chai.find(c => c.length > 5)); // 'cutting'
The length property is not a count of items — it's the highest index + 1. You can set it to truncate: arr.length = 2 removes everything after index 1.
These three methods are the backbone of functional-style JavaScript. Master them and you'll write cleaner, more predictable code.
const prices = [120, 45, 380, 22, 750, 60];
// map — transform all
const withGST = prices.map(p => p * 1.18);
// filter — keep matching
const affordable = prices.filter(p => p < 100); // [45, 22, 60]
// reduce — accumulate
const total = prices.reduce((sum, p) => sum + p, 0); // 1377
// Chaining — pipeline
const affordableWithGST = prices
.filter(p => p < 100)
.map(p => (p * 1.18).toFixed(2));
// ["53.10", "25.96", "70.80"]
// find vs filter
const first = prices.find(p => p > 100); // 120 (single value)
const all = prices.filter(p => p > 100); // [120, 380, 750]
map, filter, reduce never mutate the original array — they always return a new one. This is why Angular and NgRx love them: pure transformations that don't break change detection.
forEach is for side effects only — it returns undefined. Never use it when you need a result. Use map instead.
Objects store key-value pairs. Keys are strings (or Symbols), values can be anything — including other objects and arrays.
const user = {
name: 'Sai',
city: 'Hyderabad',
skills: ['Angular', 'Spring Boot'],
age: 26,
};
// Dot vs bracket
console.log(user.name); // 'Sai'
console.log(user['city']); // 'Hyderabad' — use when key is dynamic
// Destructuring
const { name, city, age = 25 } = user; // age has default
const { name: devName } = user; // rename to devName
// Spread — shallow copy & merge
const updated = { ...user, city: 'Mumbai' }; // original unchanged
const merged = { ...user, role: 'dev' };
// Object.entries() — iterate
Object.entries(user).forEach(([key, val]) => {
console.log(`${key}: ${val}`);
});
({ data, error } = result) is standard Angular pattern.These three operators solve the most common real-world problems in modern JavaScript.
// Spread with arrays
const a = [1, 2, 3];
const b = [4, 5, 6];
const combined = [...a, ...b]; // [1,2,3,4,5,6]
const copy = [...a]; // shallow copy
// Spread with objects
const defaults = { theme: 'dark', lang: 'en' };
const userPrefs = { lang: 'hyd', fontSize: 16 };
const config = { ...defaults, ...userPrefs };
// { theme: 'dark', lang: 'hyd', fontSize: 16 }
// Optional chaining
const user = null;
console.log(user?.address?.city); // undefined (no crash!)
console.log(user?.getName?.()); // undefined (method call)
// Nullish coalescing
const port = user?.port ?? 3000; // 3000 if null/undefined
const name = user?.name ?? 'Guest'; // 'Guest' if null/undefined
// NOT the same as ||
const count = 0 || 10; // 10 — || treats 0 as falsy
const count2 = 0 ?? 10; // 0 — ?? only checks null/undefined
?. and ?? are your best friends in Angular templates. user?.profile?.avatar ?? 'default.png' — this one line replaces 3 nested if-checks.This is one of the most misunderstood topics in JavaScript — and the source of the nastiest bugs.
// Reference trap
const original = { name: 'Sai', address: { city: 'Hyd' } };
const ref = original;
ref.name = 'Rahul'; // modifies original too!
// Shallow copy — nested still shared
const shallow = { ...original };
shallow.name = 'Kiran'; // ✅ independent
shallow.address.city = 'Mumbai'; // ❌ mutates original.address too!
// Deep copy — fully independent
const deep = structuredClone(original);
deep.address.city = 'Pune'; // ✅ original.address.city still 'Hyd'
// JSON method (old way — loses functions, Date, undefined)
const deepOld = JSON.parse(JSON.stringify(original));
// Angular NgRx pattern — always return new object
function reducer(state, action) {
return {
...state, // shallow copy state
users: [...state.users, action.user] // new array reference
};
}
Lo kar liya — Key Points:
- ✅ map/filter/reduce never mutate — they return new arrays, keeping Angular change detection happy
- ✅ Destructuring (
{name, city} = user) is standard Angular pattern for services, HTTP, router params - ✅ Spread
{...obj}creates a shallow copy — nested objects are still shared references - ✅ Use
structuredClone()for true deep copies; avoid JSON.parse/stringify (loses functions and Dates) - ✅ Optional chaining (
?.) prevents crashes on null/undefined — essential for Angular SSR code - ✅
??checks only null/undefined;||also triggers on 0, '', false — know the difference
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login