
* Modify rule S2871: Add exception for arrays of strings * S2871: Remove the exception mention and emphasize the usage of String.localeCompare
77 lines
3.6 KiB
Plaintext
77 lines
3.6 KiB
Plaintext
== Why is this an issue?
|
|
|
|
JavaScript provides built-in methods to sort arrays, making it convenient for developers to manipulate data. There are two primary ways to sort an array:
|
|
|
|
* ``++Array.prototype.sort()++``: This method sorts the elements of an array in place and returns the sorted array.
|
|
* ``++Array.prototype.toSorted()++``: This method is designed to return a new sorted array, leaving the original array unchanged.
|
|
|
|
The default sort order is lexicographic (dictionary) order, based on the string representation of the elements. This means that when sorting an array of strings, numbers, or other elements, they are converted to strings and sorted according to their Unicode code points (UTF-16). For most cases, this default behavior is suitable when sorting an array of strings.
|
|
|
|
However, it's essential to be aware of potential pitfalls when sorting arrays of non-string elements, particularly numbers. The lexicographic order may not always produce the expected results for numbers:
|
|
|
|
[source,javascript,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
const numbers = [10, 2, 30, 1, 5];
|
|
numbers.sort(); // Noncompliant: lexicographic sort
|
|
console.log(numbers); // Output: [1, 10, 2, 30, 5]
|
|
----
|
|
|
|
To sort numbers correctly, you must provide a custom comparison function that returns the correct ordering:
|
|
|
|
[source,javascript,diff-id=1,diff-type=compliant]
|
|
----
|
|
const numbers = [10, 2, 30, 1, 5];
|
|
numbers.sort((a, b) => a - b);
|
|
console.log(numbers); // Output: [1, 2, 5, 10, 30]
|
|
----
|
|
|
|
Even to sort strings, the default sort order may give unexpected results. Not only does it not support localization, it also doesn't fully support Unicode, as it only considers UTF-16 code units. For example, in the code below, `"eΔ"` is surprisingly before and after `"éΔ"`. To guarantee that the sorting is reliable and remains as such in the long run, it is necessary to provide a compare function that is both locale and Unicode aware - typically `String.localeCompare`.
|
|
|
|
[source,javascript]
|
|
----
|
|
const code1 = '\u00e9\u0394'; // "éΔ"
|
|
const code2 = '\u0065\u0301\u0394'; // "éΔ" using Unicode combining marks
|
|
const code3 = '\u0065\u0394'; // "eΔ"
|
|
console.log([code1, code2, code3].sort()); // Noncompliant: ["éΔ", "eΔ", "éΔ"], "eΔ" position is inconsistent
|
|
console.log([code1, code2, code3].sort((a, b) => a.localeCompare(b))); // ["eΔ", "éΔ", "éΔ"]
|
|
----
|
|
|
|
== Resources
|
|
=== Documentation
|
|
|
|
* MDN web docs - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort[``++Array.prototype.sort()++``]
|
|
* MDN web docs - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted[``++Array.prototype.toSorted()++``]
|
|
* MDN web docs - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare[``++String.prototype.localeCompare()++``]
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Provide a compare function to avoid sorting elements alphabetically.
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== on 27 Apr 2015, 12:57:27 Linda Martin wrote:
|
|
\[~ann.campbell.2] Assign for review and completion
|
|
|
|
=== on 28 Apr 2015, 13:28:08 Ann Campbell wrote:
|
|
Double-check my changes, please [~linda.martin]
|
|
|
|
|
|
Also, do you plan to raise this on all arrays, or limit it to when you can tell the array contains numbers?
|
|
|
|
=== on 29 Apr 2015, 09:16:26 Linda Martin wrote:
|
|
\[~ann.campbell.2] That's a good question. I think we'll do a first implementation and see what are the results and narrow the scope if too much FP shows up.
|
|
|
|
|
|
Reviewed.
|
|
|
|
endif::env-github,rspecator-view[]
|