Sorting Arrays Correctly
MedArray sorting in JavaScript has a critical gotcha: the default sort() converts elements to strings! This causes unexpected behavior with numbers. Understanding comparator functions is essential for correct sorting. This concept covers numeric sorting, string sorting with locale awareness, object sorting by properties, and the new immutable toSorted() method.
Interactive Visualization
mutation Methods
1
2
3
Key Points
- sort() converts elements to strings by default!
- Comparator: (a, b) => negative if a < b, positive if a > b, 0 if equal
- Numeric sort: arr.sort((a, b) => a - b)
- String sort: use localeCompare for proper Unicode
- Object sort: compare object properties in comparator
- toSorted() ES2023 - immutable version
Code Examples
The Number Sorting Trap
const nums = [10, 2, 30, 1, 15]; // ❌ WRONG: Default sort (converts to strings!) nums.sort(); console.log(nums); // [1, 10, 15, 2, 30] - wrong! // Why? String comparison: "10" < "2" (lexicographic) // ✅ CORRECT: Numeric comparator const nums2 = [10, 2, 30, 1, 15]; nums2.sort((a, b) => a - b); console.log(nums2); // [1, 2, 10, 15, 30] - correct! // How comparator works: // if a - b < 0: a comes first // if a - b > 0: b comes first // if a - b === 0: keep order
sort() converts to strings. Always provide comparator for numbers: (a, b) => a - b
Descending Order
const nums = [3, 1, 4, 1, 5]; // Descending: b - a (reverse order) nums.sort((a, b) => b - a); console.log(nums); // [5, 4, 3, 1, 1] // Or negate ascending nums.sort((a, b) => -(a - b)); // Remember: positive result = b comes first
For descending order, reverse the comparison: (a, b) => b - a
Sorting Objects by Property
const users = [ { name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }, { name: 'Carol', age: 35 } ]; // Sort by age users.sort((a, b) => a.age - b.age); console.log(users.map(u => u.name)); // ['Bob', 'Alice', 'Carol'] // Sort by name (string) users.sort((a, b) => a.name.localeCompare(b.name)); console.log(users.map(u => u.name)); // ['Alice', 'Bob', 'Carol'] // Multi-field sort (age desc, then name asc) users.sort((a, b) => { if (b.age !== a.age) { return b.age - a.age; // Age descending } return a.name.localeCompare(b.name); // Name ascending });
Compare object properties in comparator. Use localeCompare for strings.
Immutable Sorting (ES2023)
const original = [3, 1, 4, 1, 5]; // ❌ OLD: Mutates original const sorted = [...original].sort((a, b) => a - b); // ✅ NEW: toSorted() (ES2023) const sorted2 = original.toSorted((a, b) => a - b); console.log(original); // [3, 1, 4, 1, 5] - unchanged! console.log(sorted2); // [1, 1, 3, 4, 5] // Other immutable methods const reversed = original.toReversed(); const spliced = original.toSpliced(1, 2, 'x', 'y'); const replaced = original.with(2, 'new'); // All return new arrays, leave original unchanged
ES2023 adds toSorted(), toReversed(), toSpliced(), and with() for immutable array operations.
Common Mistakes
- Using default sort() on numbers
- Forgetting sort mutates the original array
- Not using localeCompare for international strings
- Returning boolean from comparator instead of number
Interview Tips
- Always remember: default sort converts to strings!
- Know the numeric comparator: (a, b) => a - b
- Know how to sort objects by property
- Know about toSorted() for immutable sorting