Search justacoding.blog. [Enter] to search. Click anywhere to close.

April 25th, 2022

9 Useful JavaScript Utility Functions

JavaScript utility functions are efficient, reusable snippets that are generic in nature and can be utilized across many different projects. To this end, the overall purpose of the utility function in JavaScript is to help increase your productivity as well as the consistency of your code.

In this article, we’ll go through some handy functionalities that could prove useful in your next project.

So, with that said, let’s begin looking at the various JavaScript utility functions and discuss their many different applications and uses.

1. Do something x times

The requirement to do something x times is (perhaps) surprisingly common in JavaScript.

Here’s a simple utility function to accomplish this very task in a neat and manageable wrapper:

const times = (times, func) => {
  if (isNaN(times)) {
    console.error("times to run must be specified")
    return
  }
  if (typeof func !== "function") {
    console.error(`func must be a valid function, ${typeof func} provided`)
    return
  }
  Array.from(Array(times)).forEach(() => {
    func()
  })
}

times(3, () => console.log("hello"))

Many JavaScript libraries implement this kind of helper utility, for instance Underscore’s _.times function.

As you may expect, there are many ways to do something x times in JavaScript.

Utilizing a utility function like the one provided above is a good way to ensure consistency across your project(s), and of course, if you need to modify the underlying functionality in some way — you’ll only need to impact one area of your code.

2. Generate a random number within a specified range

Here’s a simple but verbose wrapper around the classic approach to generating a random (whole) number in JavaScript:

const getRandomNumberInRange = (lower = 0, upper = 10) => {
  if (isNaN(lower) || isNaN(upper)) {
    console.error("lower and upper must be valid numbers")
    return
  }
  lower = Math.ceil(lower)
  upper = Math.floor(upper)
  return Math.floor(Math.random() * (upper - lower + 1)) + lower
}

Although the operations required to generate a random number are fairly straightforward, it can be handy to have a ready-made function whereby it’s possible to pass in the various parameters based on the specific requirement at hand.

Having a simple, concise function as above also helps to promote clear, readable code in general.

3. Shorten a string with ellipsis

It can be useful to shorten or trim down a piece of text in order to make it fit within a given space, or to keep the string consistently formatted along with its counterparts.

It’s often possible to achieve this effect via CSS alone (using text-overflow: ellipsis), but that depends very much on the use case. There are still some scenarios where a JavaScript equivalent could prove much more useful.

So in terms of implementing this requirement as a JavaScript utility function in particular, you can use a snippet like the following:

const shorten = (text, length = 10, ellipsisCount = 3) => {
  if (!(typeof text === "string" || text instanceof String)) {
    console.error(`expecting a string, ${typeof text} provided`)
    return ""
  }
  if (isNaN(length) || isNaN(ellipsisCount)) {
    console.error("length and ellipsisCount must be valid numbers")
    return
  }
  
  if (text.length <= length) {
    return text
  }
  const ellipsis = Array.from(Array(ellipsisCount)).map(() => ".").join("")
  return `${text.substr(0, length)}${ellipsis}`
}

shorten("I am some text", 4, 2) // I am..

So this will firstly shorten your string to the specified length – then append the required number of elipses to the end of this resultant string.

Why use JavaScript to provide ellipses, though?

The benefit of this JavaScript approach (as opposed to the CSS approach referenced above) is that you can more easily modify the behaviour of the text-shortening.

For instance, you can control exactly when the ellipsis should appear and under what condition, as well as how many ellipsis should be present in the output.

In general, this type of utility function is more powerful and provides more flexibility when compared to its CSS equivalent, but the use cases may be somewhat different to begin with, anyway.

4. Remove duplicates from an array

As you may expect, there are many possible utility functions that revolve around the manipulation and control of arrays.

One useful example is a function to strip duplicates out of an array:

const removeDuplicates = (arr) => {
  if (!Array.isArray(arr)) {
    console.error(`array expected, ${typeof arr} provided`)
    return
  }
  return [...new Set(arr)]
}

removeDuplicates(["Tom", "Simon", "Tom", "Sarah"])
// ["Tom", "Simon", "Sarah"]

It’s another one-liner, but remember, it’s good to be consistent.

There are lots of ways to remove duplicates from an array in JavaScript, so using the same approach each time promotes clearer and more robust code in the long run.

That’s why it may still be a good decision to extract even one-liners such as this one to their own dedicated utility functions.

5. Debounce (or delay) a function

There will be occasions where you’ll want to limit or hinder the execution of a function based on a given condition.

The classic example of this is a form that triggers a network request on user input. So when the user types into the search field, a network request should be executed to fetch the search results.

(You can check out an example of this in practice in our React Autocomplete tutorial).

However, it’s inefficient and wasteful to trigger a request on literally every key press. It’d be much better to trigger this request once the user actually stops typing.

That’s where a JavaScript utility function to debounce the underlying execution would come in handy:

const debounce = (func, timeout = 2500) => {
  if (typeof func !== "function") {
    console.error(`func must be a valid function, ${typeof func} provided`)
    return
  }
  let timer
  return (...args) => {
    clearTimeout(timer)
    timer = setTimeout(() => { 
      func.apply(this, args) 
    }, timeout)
  }  
}

How this function works

This is what’s known as a closure.

timer effectively retains it’s own state within this block (function). Every time debounce is called, timer is cleared.

If timer isn’t cleared before the specified timeout (in this case, 2.5 seconds) — the functionality (dictated by the func parameter) is finally invoked. Thus, you can see how this function can be used to hinder or delay invocation using this logic.

This is what’s known as debouncing, and this is a debounce utility function in its most simplistic form.

As the function is generic, it can be applied in many different scenarios, not only to throttle a network request in particular.

Note: A handy side-effect is that it’ll naturally prevent unwanted “spamming” – if a user (for some reason) keeps repeatedly clicking a given button, for instance – debouncing will only allow the resultant functionality to invoked after the spamming has ceased.

6. Measure the performance/time taken of a function

If you’ve ever wondered how long (specifically) a function takes in JavaScript, you’ll be glad to know there is in-built functionality you can utilize out of the box. There are various methods on the console object to measure the time taken of a function.

Here’s a convenient wrapper which can be used to wrap your target functionality and output the time taken for debugging or performance-monitoring purposes:

const measureTime = (func, label = "default") => {
  if (typeof func !== "function") {
    console.error(`func must be a valid function, ${typeof func} provided`)
    return
  }
  console.time(label)
  func()
  console.timeEnd(label)
}

measureTime("findPeople", someExpensiveFindPeopleFunction)
// findPeople: 13426.336181640625ms

So you’ll see the time taken (in milliseconds – ms) of the specified operation.

7. Slugify a string

Imagine you are designing a CMS (content management system) and you need a way to generate a browser-friendly URL for the user-generated blog posts.

To do this, you’ll likely want to slugify the title of each blog post:

const slugify = (text) => {
  if (!(typeof text === "string" || text instanceof String)) {
    console.error(`string expected, ${typeof str} provided`)
    return str
  }
  return text.toLowerCase()
    .replace(/ /g, "-")
    .replace(/[^\w-]+/g, "")
}

slugify("Hello, everyone!") // hello-everyone

So this function is responsible from converting some regular text or content (ie. written in plain English) to a browser-friendly URL. This involves the removal of special characters, converting spaces to hyphens and so on, as demonstrated.

This is a standard routine for many different types of system, especially those that accept user input.

By default, the user won’t always decide on the final URL. But that final URL can be inferred based on some other parameters (ie. post title) using a utility function such as this one.

8. Camel case to snake case, and vice-versa

It can be useful to convert from one of these two common casings to the other, and vice-versa.

Here’s how you can convert camel case to snake case in JavaScript:

const camelToSnakeCase = (text) => {
  if (!(typeof text === "string" || text instanceof String)) {
    console.error(`string expected, ${typeof text} provided`)
    return text
  }
  return text.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
}

camelToSnakeCase("camelCaseToSnakeCase") // camel_case_to_snake_case

And here’s the inverse, snake case to camel case:

const snakeToCamelCase = (text) => {
  if (!(typeof text === "string" || text instanceof String)) {
    console.error(`string expected, ${typeof text} provided`)
    return text
  }
  text
    .toLowerCase()
    .replace(/([-_][a-z])/g, group =>
      group
        .toUpperCase()
        .replace("-", "")
        .replace("_", "")
    )
}

snakeToCamelCase("snake_case_to_camel_case") // snakeCaseToCamelCase

These are ideal use cases for JavaScript utility functions, as you don’t necessarily want to repeat these same functionalities multiple times across multiple projects!

It’s much better to have a simple helper function that you can easily and efficiently reuse for tasks such as these ones.

In each case, we’re checking for valid input (the supplied string), otherwise we’ll encounter an error lower down in the code. We can’t call substring or toLowerCase to an array or a null variable, for example.

9. Validate an email address

Of course, when dealing with user input, you’ll more than likely want some kind of frontend validation in place.

Validating a user’s email address in JavaScript is one example of this:

const emailIsValid = (email) => {
  if (!(typeof email === "string" || email instanceof String)) {
    console.error(`string expected, ${typeof email} provided`)
    return false
  }
  const expression = /\S+@\S+\.\S+/
  return expression.test(email)
}

emailIsValid("somebody@somewhere.com") // true
emailIsValid("nobody@nowhere") // false

You may have many forms across your site, and you’ll want to validate the email address input in each case. That’s where this utility function would come in handy.

Frontend validation like this should be seen as the “first pass” — you’ll likely want to be validating this kind of data in the backend, prior to save, also.

There are many other types of user input that are suitable to handle via these JavaScript utility functions.

Mobile phone numbers, addresses and postcodes would be other classic candidates to handle via utility functions in this regard, for example.

Do I need to write my own utility functions?

No!

You don’t need to write your own.

There are many libraries out there, two of the more popular ones being Underscore.js and Lodash.

There are also more specific libraries that each deal with a specific areas of JavaScript, date-fns being a good example of a date-oriented utility library, for instance.

However…

You should consider if you really need a utility library to begin with.

These libraries can typically add a lot of bloat to your project — and these days, a lot of the functionality contained within may indeed be redundant.

Back in the day, it can be argued that the use of Lodash (and similar libraries) was a lot more necessary. Writing up your own version of these various utility functions in JavaScript was tedious and long-winded.

Nowadays, JavaScript can provide many of the required functionalities out of the box. You can read a lot about the new functionalities contained within various JavaScript versions, you’ll notice that there is, in places, considerable overlap with these functionalities when contrasted with a utility library like Lodash or Underscore.

A happy medium

A happy medium may be to drop the standard utility libraries, but build up your own lightweight variant and couple that with the more powerful JavaScript features contained in ES5 and onwards.

This way, you can save on the extra bloat and get more direct usage out of the new(er) JavaScript features first-hand.

It’s also a lot more fun (and conducive to learning) to write your own simple utility helpers!

Thanks for reading!

Have any questions? Ping me over at @justacodingblog
← Back to blog