How to Dynamically Sort an Array of Objects in JavaScript

How to Dynamically Sort an Array of Objects in JavaScript

In this JavaScript tutorial show you how to dynamically sort an array of objects in JavaScript, using Array.prototype.sort() and a custom compare function.

If you have an array of objects that you need to sort into a certain order, you might be tempted to reach for a JavaScript library. But before you do, remember that you can do some pretty neat sorting with the native Array.sort function.

In this article, we’ll show you how to sort an array of objects in JavaScript with no fuss or bother.

Sort an array of objects in JavaScript

Basic Array Sorting

By default, the JavaScript Array.sort function converts each element in the array that needs to be sorted into a string, and compares them in Unicode code point order.

const foo = [9, 1, 4, 'zebroid', 'afterdeck'];
foo.sort(); // returns [ 1, 4, 9, 'afterdeck', 'zebroid' ]

const bar = [5, 18, 32, new Set, { user: 'Eleanor Roosevelt' }];
bar.sort(); // returns [ 18, 32, 5, { user: 'Eleanor Roosevelt' }, Set {} ]

You may be wondering why 32 comes before 5. Not logical, huh? Well, actually it is. This happens because each element in the array is first converted to a string, and "32" comes before "5" in Unicode order.

It’s also worth noting that unlike many other JavaScript array functions, Array.sort actually changes, or mutates the array it sorts.

const baz = ['My cat ate my homework', 37, 9, 5, 17];
baz.sort(); // baz array is modified
console.log(baz); // shows [ 17, 37, 5, 9, 'My cat ate my homework' ]

To avoid this, you can create a new instance of the array to be sorted and modify that instead. This is possible using an array method that returns a copy of the array. For example, Array.slice:

const sortedBaz = baz.slice().sort(); // a new instance of the baz array is created and sorted

Or if you prefer a newer syntax, you can use the spread operator for the same effect:

const sortedBaz = [...baz].sort(); // a new instance of the baz array is created and sorted

The output is the same in both cases:

console.log(baz); // ['My cat ate my homework', 37, 9, 5, 17];
console.log(sortedBaz); // [ 17, 37, 5, 9, 'My cat ate my homework' ]

Try it out

Using Array.sort alone wouldn’t be very useful for sorting an array of objects. Thankfully, the function takes an optional compareFunction parameter, which causes the array elements to be sorted according to the return value of the compare function.

Using Compare Functions to Sort

Let’s say that foo and bar are the two elements being compared by the compare function, and the return value of the compare function is set up as follows:

  1. less than 0 — foo comes before bar
  2. greater than 0  — bar comes before foo
  3. equal to 0  — foo and bar are left unchanged with respect to each other.

Let’s look at a simple example with an array of numbers:

const nums = [79, 48, 12, 4];

function compare(a, b) {
  if (a > b) return 1;
  if (b > a) return -1;

  return 0;
}

nums.sort(compare);
// => 4, 12, 48, 79

We can refactor this a little, as subtracting a from b will also give us the return value:

function compare(a, b) {
  return a - b;
}

This is now a good candidate for an arrow function:

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

How to Sort an Array of Objects in JavaScript

Now let’s look at sorting an array of objects. For this demo we’ll use an array of singers:

const singers = [
  { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
];

We can use the following compare function to sort this array of singers according to their band:

function compare(a, b) {
  // Use toUpperCase() to ignore character casing
  const bandA = a.band.toUpperCase();
  const bandB = b.band.toUpperCase();

  let comparison = 0;
  if (bandA > bandB) {
    comparison = 1;
  } else if (bandA < bandB) {
    comparison = -1;
  }
  return comparison;
}

singers.sort(compare);

/* returns [
  { name: 'Steven Tyler', band: 'Aerosmith',  born: 1948 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 }
] */

To reverse the sorting order, you can invert the return value of the compare function:

function compare(a, b) {
  ...

  //invert return value by multiplying by -1
  return comparison * -1;
}

Try it out

Creating a Dynamic Sorting Function

Let’s finish up by making this more dynamic. Let’s create a sorting function, which you can use to sort an array of objects, whose values are either strings or numbers. This function has two parameters — the key we want to sort by and the order of the results (i.e. ascending or descending):

const singers = [
  { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
];

function compareValues(key, order = 'asc') {
  return function innerSort(a, b) {
    if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
      // property doesn't exist on either object
      return 0;
    }

    const varA = (typeof a[key] === 'string')
      ? a[key].toUpperCase() : a[key];
    const varB = (typeof b[key] === 'string')
      ? b[key].toUpperCase() : b[key];

    let comparison = 0;
    if (varA > varB) {
      comparison = 1;
    } else if (varA < varB) {
      comparison = -1;
    }
    return (
      (order === 'desc') ? (comparison * -1) : comparison
    );
  };
}

And this is how you’d use it:

// array is sorted by band, in ascending order by default
singers.sort(compareValues('band'));

// array is sorted by band in descending order
singers.sort(compareValues('band', 'desc'));

// array is sorted by name in ascending order
singers.sort(compareValues('name'));

// array is sorted by date if birth in descending order
singers.sort(compareValues('born', 'desc'));

Try it out

In the code above, the hasOwnProperty method is used to check if the specified property is defined on each object and has not been inherited via the prototype chain. If it’s not defined on both objects, the function returns 0, which causes the sort order to remain as is (i.e. the objects remain unchanged with respect to each other).

The typeof operator is also used to check the data type of the property’s value. This allows the function to determine the proper way to sort the array. For example, if the value of the specified property is a string, a toUpperCase method is used to convert all its characters to uppercase, so character casing is ignored when sorting.

You can adjust the above function to accommodate other data types, and any other needs your script may have.

String.prototype.localeCompare()

In our example above, we want to be able to sort an array of objects, whose values are either strings or numbers. If, however, you know that you’ll only be dealing with objects whose values are strings, you can tidy up the code a little using JavaScript’s localeCompare method.

This method returns a number indicating whether a string comes before, after, or is the same as a given string in the sort order. It enables a case-insensitive sort of an array:

['bjork', 'Bjork', 'Björk'].sort();
// [ 'Bjork', 'Björk', 'bjork' ]

['bjork', 'Bjork', 'Björk'].sort((a, b) => a.localeCompare(b));
//  [ 'bjork', 'Bjork', 'Björk' ]

In terms of our compareValues function, that means we could write:

function compareValues(key, order = 'asc') {
  return function innerSort(a, b) {
    if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) return 0;
    const comparison = a[key].localeCompare(b[key]);

    return (
      (order === 'desc') ? (comparison * -1) : comparison
    );
  };
}

You can read more about localeCompare over on MDN.

Conclusion

So there you have it — a short introduction to sorting an array of objects using vanilla JavaScript. Although many libraries offer this kind of dynamic sorting ability, as demonstrated, it’s not all that hard to implement this functionality yourself. Plus it’s good to understand what is going on under the hood.

JavaScript Array Webdev ES6

What's new in Bootstrap 5 and when Bootstrap 5 release date?

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Random Password Generator Online

HTML Color Picker online | HEX Color Picker | RGB Color Picker

How to Clone an Array in JavaScript?

In this JavaScript tutorial, you'll learn how to clone an array in JavaScript. Because arrays in JS are reference values, so when you try to copy it using the = it will only copy the reference to the original array and not the value of the array.

JavaScript: Array Destructuring (ES6)

Complete Guide to Unpack Values from Arrays

Convert String To Array Using Javascript Split Method

In this tutorial, you’ll be going to learn how to convert string to array using javascript split method. The easiest approach to use javascript built-in method String.split(). JavaScript split string method return array of a substring after splitting a string based on the separator you provide. The separator might be a string, special character or […]

JavaScript ES6 Classes

An exciting new construct that was introduced in the ES6 specification is the ES6 classes. If you're a Javascript developer, you will be aware that Javascript follows prototypal inheritance and sometimes it can get a little messy. However, with ES6 classes the syntax is simpler and much more intuitive.

ES6 Way to Clone an Array

In this ES6 tutoria, you'll leran how to clone array in ES6. The spread operator in ES6 is used to clone an array, whereas slice() method in JavaScript is an older way that provide 0 as the first argument. These methods create a new, independent array and copy all the elements of oldArray to the new one i.e. both these methods do a shallow copy of the original array.