JavaScript Array Sort Method: The Complete Guide to Sorting Strings and Numbers
In this article, we will learn Array sort method.
Understanding the Basics
The sort() method sorts the elements of an array in place and returns the sorted array. Here's the key insight: by default, sort() converts all elements to strings and sorts them lexicographically.
const fruits = ['banana', 'apple', 'cherry', 'date'];
console.log(fruits.sort()); // ['apple', 'banana', 'cherry', 'date']
Syntax
array.sort([compareFunction])
Without compareFunction: Sorts as strings
With compareFunction: Uses custom logic to determine order
How Sort Works for Strings
When sorting strings, JavaScript uses lexicographic order (dictionary order) based on UTF-16 code units.
Basic String Sorting
const names = ['John', 'Alice', 'Bob', 'Charlie'];
names.sort();
console.log(names); // ['Alice', 'Bob', 'Charlie', 'John']
Case Sensitivity in String Sorting
Here's where it gets interesting:
const mixed = ['apple', 'Banana', 'cherry', 'Date'];
mixed.sort();
console.log(mixed); // ['Banana', 'Date', 'apple', 'cherry']
Why? Capital letters have lower UTF-16 values than lowercase letters:
'A' = 65, 'B' = 66, 'C' = 67...
'a' = 97, 'b' = 98, 'c' = 99...
Case-Insensitive String Sorting
const mixed = ['apple', 'Banana', 'cherry', 'Date'];
// Case-insensitive sort
mixed.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
console.log(mixed); // ['apple', 'Banana', 'cherry', 'Date']
Locale-Aware String Sorting
For international applications, use localeCompare():
const words = ['café', 'resume', 'naïve', 'jalapeño'];
words.sort((a, b) => a.localeCompare(b));
console.log(words); // Properly sorted considering accents
The Number Sorting Problem
Here's the classic JavaScript gotcha:
const numbers = [10, 2, 30, 4, 1];
console.log(numbers.sort()); // [1, 10, 2, 30, 4] - NOT what we want!
Why This Happens
JavaScript converts numbers to strings before sorting:
10becomes"10"2becomes"2"30becomes"30"4becomes"4"
Then it sorts alphabetically:
"1"comes before"2""10"comes before"2"(because"1"<"2")"30"comes before"4"(because"3"<"4")
The Solution: Compare Functions
const numbers = [10, 2, 30, 4, 1];
// Ascending order (smallest to largest)
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 2, 4, 10, 30]
// Descending order (largest to smallest)
numbers.sort((a, b) => b - a);
console.log(numbers); // [30, 10, 4, 2, 1]
Compare Functions Explained
The compare function is the heart of custom sorting. It takes two arguments and returns:
Negative value (< 0): First argument comes before second
Zero (0): Elements are equal
Positive value (> 0): First argument comes after second
How a - b Works for Numbers
Let's trace through the logic:
const numbers = [5, 2, 8];
// When comparing 5 and 2:
// a = 5, b = 2
// a - b = 5 - 2 = 3 (positive)
// Since 3 > 0, 'a' (5) comes after 'b' (2)
// When comparing 2 and 8:
// a = 2, b = 8
// a - b = 2 - 8 = -6 (negative)
// Since -6 < 0, 'a' (2) comes before 'b' (8)
// Result: [2, 5, 8]
Visual Example with Logging
const numbers = [4, 2, 7, 1];
numbers.sort((a, b) => {
const result = a - b;
console.log(`Comparing ${a} and ${b}: ${a} - ${b} = ${result}`);
console.log(`Decision: ${result < 0 ? `${a} before ${b}` : result > 0 ? `${a} after ${b}` : 'equal'}`);
return result;
});
// This will show you exactly how the sorting decisions are made
Advanced Sorting Techniques
Sorting Objects by Property
const students = [
{ name: 'Alice', grade: 85, age: 20 },
{ name: 'Bob', grade: 92, age: 19 },
{ name: 'Charlie', grade: 78, age: 21 }
];
// Sort by grade (ascending)
students.sort((a, b) => a.grade - b.grade);
// Sort by name (alphabetically)
students.sort((a, b) => a.name.localeCompare(b.name));
// Sort by age (descending)
students.sort((a, b) => b.age - a.age);
Multi-Level Sorting
const employees = [
{ department: 'IT', name: 'John', salary: 70000 },
{ department: 'HR', name: 'Jane', salary: 65000 },
{ department: 'IT', name: 'Bob', salary: 75000 },
{ department: 'HR', name: 'Alice', salary: 60000 }
];
// Sort by department first, then by salary (descending)
employees.sort((a, b) => {
// Primary sort: department
if (a.department !== b.department) {
return a.department.localeCompare(b.department);
}
// Secondary sort: salary (if departments are equal)
return b.salary - a.salary;
});
console.log(employees);
// HR employees first (Alice, Jane), then IT employees (Bob, John)
// Within each department, sorted by salary (highest first)
Sorting by String Length
const words = ['elephant', 'cat', 'dog', 'butterfly', 'ant'];
// Sort by length (shortest first)
words.sort((a, b) => a.length - b.length);
console.log(words); // ['cat', 'dog', 'ant', 'elephant', 'butterfly']
// Sort by length (longest first)
words.sort((a, b) => b.length - a.length);
console.log(words); // ['butterfly', 'elephant', 'cat', 'dog', 'ant']
Custom Sorting Logic
const tasks = [
{ name: 'Task A', priority: 'high', completed: false },
{ name: 'Task B', priority: 'low', completed: true },
{ name: 'Task C', priority: 'medium', completed: false },
{ name: 'Task D', priority: 'high', completed: true }
];
// Sort by completion status first, then by priority
tasks.sort((a, b) => {
// Incomplete tasks first
if (a.completed !== b.completed) {
return a.completed ? 1 : -1;
}
// Then by priority (high > medium > low)
const priorityOrder = { 'high': 3, 'medium': 2, 'low': 1 };
return priorityOrder[b.priority] - priorityOrder[a.priority];
});
Performance Considerations
Understanding Sort Complexity
JavaScript's sort typically uses Timsort (a hybrid stable sorting algorithm):
Time complexity: O(n log n) average case
Space complexity: O(n)
Stable sort: Equal elements maintain their relative order
Memory Considerations
// sort() modifies the original array
const original = [3, 1, 4, 1, 5];
const sorted = original.sort((a, b) => a - b);
console.log(original); // [1, 1, 3, 4, 5] - original is modified!
console.log(sorted === original); // true - same reference
// To keep original unchanged
const original = [3, 1, 4, 1, 5];
const sorted = [...original].sort((a, b) => a - b);
// or
const sorted = original.slice().sort((a, b) => a - b);
Real-World Examples
E-commerce Product Sorting
const products = [
{ name: 'Laptop', price: 999.99, rating: 4.5, category: 'Electronics' },
{ name: 'Phone', price: 699.99, rating: 4.8, category: 'Electronics' },
{ name: 'Book', price: 19.99, rating: 4.2, category: 'Education' },
{ name: 'Headphones', price: 199.99, rating: 4.6, category: 'Electronics' }
];
// Sort by price (low to high)
products.sort((a, b) => a.price - b.price);
// Sort by rating (high to low)
products.sort((a, b) => b.rating - a.rating);
// Sort by category, then by price within category
products.sort((a, b) => {
if (a.category !== b.category) {
return a.category.localeCompare(b.category);
}
return a.price - b.price;
});
Date Sorting
const events = [
{ name: 'Meeting', date: new Date('2024-01-15') },
{ name: 'Conference', date: new Date('2024-01-10') },
{ name: 'Workshop', date: new Date('2024-01-20') }
];
// Sort by date (earliest first)
events.sort((a, b) => a.date - b.date);
// Sort by date (latest first)
events.sort((a, b) => b.date - a.date);
Key Takeaways
Default behavior:
sort()converts elements to strings and sorts lexicographicallyFor numbers: Always use a compare function
(a, b) => a - bFor strings: Consider case sensitivity and locale with
localeCompare()Compare function: Return negative, zero, or positive values to control order
In-place sorting:
sort()modifies the original arrayStable sort: Equal elements maintain their relative order
Performance: O(n log n) time complexity, minimize work in compare function