Optionally chaining String.replace()
Tags: javascript, functional, productivity
Published: 2020-10-02 07:18:53

---
title: Optionally chaining String.replace()
published: true
date: 2020-10-01 00:00:00 UTC
tags: javascript, functional, productivity
canonical_url: https://jonathanland.design/articles/optionally-chaining-string-replace
---

Using ternaries and a bit of regex magic, we can add inline logic to `String.replace()` statements. Here's a slightly contrived example, using the [named function parameters pattern](https://jonathanland.design/articles/named-function-parameters-in-es6):

```js
const presentableUrl = (fullUrl, { removeProtocol = true, removeWww = false } = {}) =>
  fullUrl
    .replace(/(https?:\/\/)/i, removeProtocol ? '' : '$1')
    .replace(/(www\.)/i, removeWww ? '' : '$1')
```

## How

What's going on here, you ask?

`String.replace()` has two important properties: It returns a new string, so we can chain calls; and it allows us to replace a substring with any [matched group](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges#Using_groups) in the search pattern. This is done with a special string like `'$1'`, where the number after the `$` represents the index of the group, counting from 1. This means that by grouping our entire pattern (i.e. surrounding it with round brackets), we can then refer to the entire match as `'$1'`.

We then use the original match as the falsy expression of a [ternary statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator). This means that if the condition evaluates to `false`, it returns an identical string, effectively short-circuiting _that specific `replace`_.

So the line

```js
fullUrl.replace(/(https?:\/\/)/i, removeProtocol ? '' : '$1')
```

can be translated to pseudocode as

```text
replace _match_ with
    if removeProtocal is true
        ''
    else
        _match_ /* replace it with itself */

```

## Why

Writing functions that perform a sequence of string transformations is quite common. In most cases we want the functions to be [pure](https://en.wikipedia.org/wiki/Pure_function) — a `string` goes in, a `string` comes out, and that's that. Simple. One-linery. Arrow-functiony.

However, if we want relatively generic functions, we sometimes need to allow _optional transformations_. So where do we insert that condition in our function's logic? We _could_ just put it in an `if` statement. The earlier example would become:

```js
function presentableUrl (fullUrl, { removeProtocol = true, removeWww = false } = {}) {
  let url = fullUrl

  if (removeProtocol) {
    url = url.replace(/https?:\/\//i, '')
  }

  if (removeWww) {
      url = url.replace(/www\./i, '')
  }

  return url
}
```

A bit of cringe-worthy, isn't it? We now have internal variable to track, and any condition we add in the future brings along another `if` statement and 3 lines of code. It's gonna get long. Also, it's not immeadtely clear from looking at this function that all it does is `string` in,`string` out — someone (e.g. future us) could accidentally add non-pure functionality to it, and it wouldn't be immediately obvious.

This is exactly the kind of problem that [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) and ternaries help us solve.

## When

I've tagged this pattern an Elegant Footgun™, and it defiantly makea it easy to shoot yourself in the foot.

Code-superlatives like "beautiful", "elegant" and "readable" can be very personal and depend on many factors. Personally, I find this pattern to be an elegant, readable expression of simple logic ("beautiful" would be pushing it).

I'm also emotionally prepared for the day I find myself staring at my code, trying in vain to re-understand my own cleverness. If that day comes, I hope I'll be gald I wrote this article.