String#reverse method

Hello! First post here, hopefully I'm doing it right.

We got the Array.prototype.reverse method a while ago, which reverses an array in place as well as returning the result. This is a useful feature, and one that I think would be useful for strings.

Currently implementing this in a library (naively) would look something like:

String.prototype.reverse = function() {
    return this.split("").reverse().join("");
};

This does not reverse the string in place, instead returning the result. This makes sense given that strings are primitives.

This seems like it would be a relatively easy feature to implement, with a fairly low chance of breaking any existing code. The advantages of having this as a builtin are:

  • It will likely be faster than the naive implementation above
  • It will reduce the number of external libraries or custom functions required, making code shorter and/or cleaner
  • It would make sense for strings to have a reverse method if arrays do, given that it's a fairly common operation for both data types

Interested to see if others have noticed this, or think it's a good idea!

this was brought up before (don't remember where). the problem is there are utf8/utf16 characters (like emojis) that are actually multiple-characters, and do not reverse well:

let str = "👶";
str.split("").reverse().join("");
// "��"

I actually think that might be a useful reason to add it; those same issues would be encountered if you used a for loop or .split("").reverse().join(""), adding way more complexity that the programmer needs to worry about before they can properly reverse a string.

Maybe it could take an optional argument for whether it should correctly handle combining/multiple codepoint characters? It would be harder to implement, but I imagine there are existing implementations that could be copied.

Another idea might be to have it take a function as an optional argument that would return whether a character combines with the previous one; that makes it so that the programmer can choose if certain strings or types of character are treated as a single one or not.

Might be too different from what we currently have but I think it would work well.

While I would use this often, the challenge is indeed as Kai indicated: strings by default split on code units, and iterate on code points (like 💩). However, what you actually want most of the time is to do both on grapheme clusters - in other words, you want 🏳️‍🌈 to be one "thing", when it's in fact 4 code points and 6 code units. Intl.Segmenter (https://github.com/tc39/proposal-intl-segmenter) is likely the best option here, but the language (262) can't specify anything that lacks reasonable default behavior in the absence of Intl (402), so I'm not sure how that would work out.

1 Like

Using the string iterator would fix this:

let str = "👶";
Array.from(str).reverse().join("");

But as @ljharb indicated, the problem is even deeper than that.

Out of pure curiosity: what are some of the use cases for reversing a string?

I think this is a working method for reversing strings while respecting unicode characters:

function badReverse(str) {
  return str.split('').reverse().join('');
}

function goodReverse(str) {
  let c = [];
  str.replace(/[\u{0000}-\u{10FFFF}]/gu, (char) => {
    c.unshift(char);
  });
  return c.join('');
}

console.log(badReverse('😉abc😱ḉ123是👶'));
// ��是321ḉ��cba��

console.log(goodReverse('😉abc😱ḉ123是👶'));
// 👶是321ḉ😱cba😉
1 Like

I re-checked my public code, and turns out I don't have many :-) the private code I believe used it is no longer accessible to me.

1 Like