How to Sort an Array of Strings While Ignoring Case in JavaScript
When you sort an array of strings in JavaScript using the default Array.prototype.sort() method, it performs a case-sensitive sort based on Unicode code points. This leads to the unintuitive result where all uppercase letters come before all lowercase letters (e.g., 'Z' comes before 'a').
To achieve a natural, case-insensitive alphabetical sort, you must provide a custom comparison function to the sort() method that uses String.prototype.localeCompare().
The Core Problem: Default Sort is Case-Sensitive
The default sort() method does not produce a natural alphabetical order when dealing with mixed-case strings.
Example of problem:
// Problem: The default sort is not what we want.
let letters = ['Z', 'c', 'a', 'B'];
letters.sort();
console.log(letters); // Output: ['B', 'Z', 'a', 'c']
// Uppercase letters are grouped before lowercase letters.
This happens because the Unicode value for 'Z' is less than the value for 'a'. To fix this, we need to tell sort() how to compare the strings in a case-insensitive way.
The Solution (Recommended): sort() with localeCompare()
The String.prototype.localeCompare() method is the standard, modern, and most robust way to compare strings according to locale-specific rules. It has built-in options to handle case sensitivity.
By providing a comparison function to sort() that uses localeCompare(), we can achieve a natural, case-insensitive sort.
let letters = ['Z', 'c', 'a', 'B'];
letters.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
console.log(letters); // Output: ['a', 'B', 'c', 'Z']
This is the recommended best practice for sorting strings in JavaScript.
How localeCompare() Works for Case-Insensitive Sorting
The a.localeCompare(b, locales, options) method is designed for sophisticated string comparison. The key for our use case is the options object.
sensitivity: 'base': This is the crucial option. It tellslocaleCompareto only consider differences in the base letters. It ignores differences in case ('a'is treated as equal to'A') and accents ('a'is treated as equal to'á').
The localeCompare() method returns a number that the sort() method can use to determine the order:
- Negative:
ashould come beforeb. - Positive:
bshould come beforea. - Zero:
aandbare equal for sorting purposes.
This return value is perfectly compatible with the sort() method's requirements, making localeCompare the ideal tool.
A Note on Mutability (Creating a Copy First)
The Array.prototype.sort() method sorts an array in place, meaning it mutates (modifies) the original array. This can lead to unexpected bugs if other parts of your code rely on the original order.
Recommended Best Practice: Always create a shallow copy of the array before sorting it if you do not intend to modify the original. The easiest way to do this is with the spread syntax (...).
let originalArray = ['Z', 'c', 'a', 'B'];
// Create a copy before sorting to preserve the original.
let sortedArray = [...originalArray].sort((a, b) =>
a.localeCompare(b, undefined, { sensitivity: 'base' })
);
console.log(sortedArray); // Output: ['a', 'B', 'c', 'Z']
console.log(originalArray); // Output: ['Z', 'c', 'a', 'B'] (Unchanged)
Conclusion
To achieve a natural, case-insensitive sort of a string array, the default sort() method is not enough.
- The recommended best practice is to provide a custom comparison function to
sort()that uses thelocaleCompare()method with thesensitivity: 'base'option:myArray.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' })); - Always create a copy of your array (e.g., with
[...arr]) before sorting if you want to avoid mutating the original data.