Programming JavaScript

Why Array.sort() Gives Wrong Results Without a Compare Function

June 21, 2026 4 min read

Sorting data is one of the most common operations in programming.

Whether you're building:

  • Ecommerce applications
  • Analytics dashboards
  • Search results
  • Financial systems
  • Reporting tools
  • Data visualizations

you'll frequently need to arrange data in a meaningful order.

JavaScript provides a built-in solution:

array.sort()

At first glance, it appears simple.

Consider:

const numbers = [1, 2, 3];

numbers.sort();

Output:

[1, 2, 3]

Everything seems correct.

However, many developers eventually encounter a surprising result:

const numbers = [1, 10, 2, 5];

numbers.sort();

console.log(numbers);

Output:

[1, 10, 2, 5]

Most people expect:

[1, 2, 5, 10]

Instead, JavaScript produces an apparently incorrect order.

This behavior often leads developers to believe:

Array.sort() is broken

In reality:

Array.sort() is working exactly as designed.

The issue lies in understanding how JavaScript performs sorting when no compare function is provided.

In this guide, you'll learn why unexpected sorting occurs, how compare functions work, and how to sort numbers, strings, dates, and objects correctly.


What You Will Learn From This Article

After reading this guide, you'll understand:

  • How Array.sort() works internally.
  • Why numeric sorting often fails.
  • The default string comparison behavior.
  • How compare functions operate.
  • Sorting numbers correctly.
  • Sorting objects and dates.
  • Performance and best practices.

Understanding the Default Behavior

Most developers assume:

sort()

means:

Sort Numerically

It does not.

By default, JavaScript converts values to strings and performs lexicographical sorting.

Example:

[1, 10, 2]

becomes:

["1", "10", "2"]

before comparison.


What Is Lexicographical Sorting?

Lexicographical sorting is essentially dictionary ordering.

Example:

Apple
Banana
Cherry

This works perfectly for text.

However, numbers behave differently.


Why Numbers Sort Incorrectly

Consider:

const numbers = [1, 10, 2];

numbers.sort();

JavaScript compares:

"1"
"10"
"2"

Character by character.

Comparison order:

"1" < "10"

Correct.

Then:

"10" < "2"

because:

1 < 2

when comparing the first character.

Result:

[1, 10, 2]

No bug exists.

Only string comparison.


Another Surprising Example

Input:

[100, 20, 3]

Converted internally:

["100", "20", "3"]

Sorted result:

[100, 20, 3]

Expected numeric order:

[3, 20, 100]

Actual order follows string rules.


How the Compare Function Works

A compare function tells JavaScript how two values should be ordered.

Example:

array.sort((a, b) => {
    return a - b;
});

Now sorting becomes numeric.


Understanding Compare Function Results

The function:

(a, b) => a - b

returns:

Negative Number

a before b

Positive Number

a after b

Zero

No Change

This simple rule powers all custom sorting.


Sorting Numbers Correctly

Ascending order:

const numbers = [1, 10, 2, 5];

numbers.sort((a, b) => a - b);

Output:

[1, 2, 5, 10]

This is usually what developers expect.


Descending Order

Example:

numbers.sort((a, b) => b - a);

Output:

[10, 5, 2, 1]

The comparison direction is reversed.


Why a - b Works

Consider:

a = 2
b = 10

Result:

2 - 10

equals:

-8

Negative value:

2 comes before 10

Exactly what we want.


Sorting Strings Properly

String sorting often works without a compare function.

Example:

const names = [
    "Alice",
    "Bob",
    "Charlie"
];

names.sort();

Output:

[
  "Alice",
  "Bob",
  "Charlie"
]

Default behavior was designed primarily for strings.


Case Sensitivity Problems

Example:

[
  "apple",
  "Banana"
]

Default sort may produce:

[
  "Banana",
  "apple"
]

because uppercase and lowercase characters have different Unicode values.


Better String Sorting

Use:

names.sort(
    (a, b) =>
        a.localeCompare(b)
);

Benefits:

  • Language awareness
  • Better alphabetical ordering
  • Improved internationalization

Sorting Objects

Common example:

const users = [

    {
        name: "John",
        age: 32
    },

    {
        name: "Alice",
        age: 25
    }
];

Sort by age:

users.sort(
    (a, b) =>
        a.age - b.age
);

Result:

Alice
John

ordered by age.


Sorting Dates

Example:

events.sort(

    (a, b) =>

        new Date(a.date)
        -
        new Date(b.date)

);

This produces chronological ordering.


Common Mistake #1

Forgetting the Compare Function

Example:

[5, 20, 100]
.sort();

Output:

[100, 20, 5]

Unexpected but correct according to string sorting rules.


Common Mistake #2

Returning Boolean Values

Incorrect:

array.sort(
    (a, b) =>
        a > b
);

The compare function should return:

Negative
Zero
Positive

not:

true
false

Results become inconsistent.


Common Mistake #3

Mutating Original Arrays Unexpectedly

Example:

const numbers = [3, 1, 2];

numbers.sort();

sort() modifies the original array.

Result:

numbers

itself changes.


Preserving the Original Array

Use:

const sorted =

    [...numbers]

    .sort(
        (a, b) =>
            a - b
    );

The original array remains untouched.


Performance Considerations

Modern JavaScript engines implement highly optimized sorting algorithms.

Complexity is typically:

O(n log n)

for average use cases.

Most performance issues arise from:

  • Expensive compare functions
  • Large object transformations
  • Repeated sorting

rather than the sorting algorithm itself.


Real-World Example

Imagine an ecommerce site.

Products:

[
  5,
  20,
  100,
  15
]

Default sorting:

products.sort();

Output:

[
  100,
  15,
  20,
  5
]

Customers see:

$100
$15
$20
$5

which appears broken.

Correct solution:

products.sort(
    (a, b) =>
        a - b
);

Now prices display properly.


Why JavaScript Was Designed This Way

Historically:

sort()

was intended primarily for string arrays.

Example:

["dog", "cat", "bird"]

Default string comparison worked naturally.

Numeric sorting required explicit instructions.

The behavior remains for backward compatibility.


Best Practices Checklist

When using Array.sort():

βœ… Use compare functions for numbers

βœ… Use localeCompare() for strings

βœ… Test sorting edge cases

βœ… Remember that sort() mutates arrays

βœ… Copy arrays when immutability matters

βœ… Sort objects by specific properties

βœ… Validate date formats before sorting

βœ… Benchmark large datasets when necessary


Common Mistakes to Avoid

Avoid:

❌ Assuming numeric sorting is automatic

❌ Returning booleans from compare functions

❌ Forgetting array mutation behavior

❌ Ignoring string case sensitivity

❌ Sorting dates as raw strings

❌ Using expensive computations inside compare functions

❌ Trusting default behavior for numeric data


Wrapping Summary

One of the most misunderstood aspects of JavaScript is that Array.sort() does not perform numeric sorting by default. Instead, it converts values to strings and applies lexicographical comparison rules, which often produces unexpected results for numbers such as 1, 10, and 2.

This behavior is not a bug but a design decision rooted in JavaScript's historical focus on string sorting. To achieve reliable numeric ordering, developers must provide a compare function that explicitly defines how values should be compared. The same principle applies when sorting objects, dates, and more complex data structures.

Understanding how compare functions work is essential for writing predictable JavaScript applications. By using appropriate comparison logic, testing edge cases, and remembering that sort() mutates the original array, developers can avoid subtle bugs and ensure their data is ordered exactly as intended.

πŸ“€ Share this article

Sign in to save

Comments (0)

No comments yet. Be the first!

Leave a Comment

Sign in to comment with your profile.

πŸ“¬ Weekly Newsletter

Stay ahead of the curve

Get the best programming tutorials, data analytics tips, and tool reviews delivered to your inbox every week.

No spam. Unsubscribe anytime.