JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
176: Implementing Common Sorting Algorithms
Imagine you're standing in front of a bookshelf where the books are in total chaos. You want to organize them by height, from shortest to tallest. You have two ways you could tackle this. You could start at the far left, compare the first two books, swap them if the left one is taller, and move one step to the right, repeating this until the tallest book eventually "bubbles" its way to the far right. Or, you could pick one random book as a benchmark—a "pivot"—and toss every book shorter than it into a pile on the left and every book taller into a pile on the right. Then, you just repeat that process for the two new piles.
In JavaScript, we have the built-in .sort() method, and honestly, you'll use it 99% of the time. But if you're heading into technical interviews or building a high-performance engine where you need to control how data is moved, you need to understand the mechanics under the hood. Let's map those bookshelf strategies to actual code.
The 'Bubble' Approach: Simple but Slow
Bubble sort is the "beginner" algorithm. It's not efficient for large datasets—it has a time complexity of O(n²)—but it's the easiest to visualize. We're basically looping through the array multiple times, swapping adjacent elements until no more swaps are needed.
function bubbleSort(arr) {
let n = arr.length;
let swapped;
do {
swapped = false;
for (let i = 0; i < n - 1; i++) {
if (arr[i] > arr[i + 1]) {
// The classic swap
[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];
swapped = true;
}
}
// After each pass, the largest element is at the end,
// so we can shrink the range we're looking at.
n--;
} while (swapped);
return arr;
}
const heights = [15, 10, 22, 8, 14];
console.log(bubbleSort(heights)); // [8, 10, 14, 15, 22]
I used destructuring assignment [a, b] = [b, a] for the swap here. It's much cleaner than the old-school temporary variable approach we used to use in C or Java.
Divide and Conquer with Quick Sort
Quick Sort is a different beast entirely. Instead of iterating through the whole list over and over, it uses recursion. We pick a pivot point, split the array into "less than" and "greater than" groups, and then sort those groups. This is significantly faster (O(n log n) on average) because it ignores huge chunks of the array as it narrows down the correct positions.
function quickSort(arr) {
// Base case: if the array has 0 or 1 elements, it's already "sorted"
if (arr.length <= 1) return arr;
const pivot = arr[Math.floor(arr.length / 2)];
const left = [];
const right = [];
const equal = [];
for (let element of arr) {
if (element < pivot) {
left.push(element);
} else if (element > pivot) {
right.push(element);
} else {
equal.push(element);
}
}
// Recursively sort the left and right, then join them with the equals
return [...quickSort(left), ...equal, ...quickSort(right)];
}
const messyBooks = [45, 12, 89, 33, 12, 7];
console.log(quickSort(messyBooks)); // [7, 12, 12, 33, 45, 89]
Notice how I handled the equal array separately. This ensures that if you have duplicate values (like two books of the exact same height), the algorithm doesn't get stuck in an infinite recursive loop or lose data.
Choosing Your Tool for the Job
You might be wondering, "Why would I ever write Quick Sort when Array.prototype.sort() exists?" The truth is, you probably won't in a standard web app. However, the logic of "Divide and Conquer" is used everywhere—from binary search trees to the way modern database indexes work. When you're dealing with millions of records, the difference between an O(n²) algorithm (Bubble) and an O(n log n) algorithm (Quick) is the difference between a page loading in 10 milliseconds or the browser freezing for 10 seconds.
📋 Practical Task
Build a Custom Contact List Sorter
You are building a contact management system. Instead of using the built-in .sort(), you need to implement a custom sorting utility that can handle an array of contact objects based on their lastName property.
Your requirements:
- Create an array of at least 5 contact objects (each should have a
firstNameand alastName). - Implement a function called
sortContactsAlphabeticallythat uses the Quick Sort logic to sort these objects by theirlastNamein ascending order. - Ensure your comparison logic handles strings correctly (remember that
"Apple" < "Banana"` is true in JavaScript). - Log the final sorted list to the console to verify the order.
// Start with this data structure:
const contacts = [
{ firstName: "Zelda", lastName: "Hyrule" },
{ firstName: "Link", lastName: "Aero" },
{ firstName: "Ganondorf", lastName: "Darkness" },
// ... add more
];There are no comments for now.