DEV Community

Cover image for How to Reverse a String in JavaScript
Anthony Harvey
Anthony Harvey

Posted on • Updated on • Originally published at anthonygharvey.com

How to Reverse a String in JavaScript

Reversing a string in JavaScript may seem like a simple task, but there are several steps involved and, in the context of a technical interview, it provides opportunities to showcase your knowledge of JavaScript and trade-offs / edge cases considered. It is good practice to make sure you understand the problem and any constraints before beginning to write code.

Some of the constraints may be given to you upfront, such as: “Write an algorithm that reverses a string in place without using built-in functions like .reverse() or .charAt(). It is always a good idea to ask clarifying questions before jumping in and attempting to solve the problem. In this case we are asked to reverse a string. Some questions we could ask include:

  1. Are there any conditions for the string that will be passed?
  2. Will the string contain regular or special characters?

Let’s start with the least amount of constraints and work our way up:

Given a string input, return a string with its characters in the reversed order of the input string.

With this challenge, we are not provided with any restrictions on the functions we can use. We can also ask our clarifying questions if the string input will contain any special characters or if there are any conditions. For this challenge, let's assume the answer is the input will only contain regular ASCII characters.

Now that we have asked our clarifying questions, you can restate the problem with the new information to buy yourself more time to think and get used to communicating your thought process out loud. You could say something like:

Given a string input of only ASCII characters, I want to create a function that returns a new string with its characters in the reverse order of the input string. I want to return a new string because I want to avoid mutating the original string input

Now that you have restated the problem as you understand it based on the responses to your clarifying questions, this may be a good point to write some simple examples.

reverse('hello') === 'olleh'
reverse('world!') === '!dlrow'
reverse('JavaScript') === 'tpircSavaJ'
Enter fullscreen mode Exit fullscreen mode

Now that we understand the problem, the input and expected output, we can break it down into steps.

  1. convert the string into an array with each character in the string as an element
  2. reverse the order of the elements in the array
  3. convert the reversed array back into a string
  4. return the reversed string
function reverse(string) {
  let answer = string.split('') // step 1
  answer.reverse()  // step 2
  answer = answer.join('')  // step 3
  return answer  //step 4
}
Enter fullscreen mode Exit fullscreen mode

Next we can test the function with the examples we created above, again communicating our thought process out loud by saying something like:

Given a string hello as an input, the function would:

  1. first split the string on each character, convert it to an array with each character as an element and assign the array to the variable answer
  2. reverse the order of the elements in the answer array
  3. join the elements in the reversed answer array into a string and reassign it to the answer variable
  4. return the answer variable, which is now a reversed string of the input

Now that the function works, we can refactor it to make it more DRY.

function reverse(string) {
  return string.split('').reverse().join('')
}
Enter fullscreen mode Exit fullscreen mode

We can also use the spread syntax inside of the array literal notation as an alternative to the .split() function.

function reverse(string) {
  return [...string].reverse().join('')
}
Enter fullscreen mode Exit fullscreen mode

Now let's suppose we are given the same problem but with more constraints

Given a string input, return a string with its characters in the reversed order of the input string without using built-in functions like .reverse(), .charAt(), the spread syntax; and without using an array.

For the sake of brevity, let's assume the same answers to our clarifying questions above. We can use the same approach for the first problem, but just with different steps given the new constraints.

  1. create a variable to serve as the return value and set it as an empty string, call it reversed
  2. loop through the characters in the input string
  3. Within each loop iteration, add the character to the beginning of the reversed string
  4. return reversed

The reason we want to add each character to the beginning of the reversed string is because if we added them to end of the string, we would just be reconstructing the input string as is and we want the return value to be a reversed string.

function reverse(string) {
  let reversed = ''  // step 1
  for(let char of string) {  // step 2
    reversed = char + reversed;  // step 3
  }
  return reversed;  // step 4
}
Enter fullscreen mode Exit fullscreen mode

In step 3 we are just concatenating the character in each iteration with the reversed string, (being careful to add it to the beginning) and reassigning the concatenated string back to the reversed variable. In other words, starting with the character and adding (concatenating) the reversed string to the end of it; then reassigning this combined string to the reversed variable.

If we put reversed = reversed + char<, that would be the opposite of what we want and would just reconstruct the input string (reverse('hello') === 'hello').

Reversing a string using a for..of loop and concatenation

Reversing a string using a for..of loop and concatenation

Also, step 2 uses the for...of statement introduced in ES2015. The syntax is easier to read and it creates a loop that iterates over iterable objects. If the interviewer asks you to not use ES2015, you can always use a traditional for loop; but if you do not have that restriction, I think using for...of loops are better because the syntax is simpler and they reduce the chances of unintentional errors being introduced (like using a comma instead of a semi-colon to separate the initial expression, condition and incremental expression).

For our last challenge, let's suppose we are given the same problem but the input strings may contain more than just ASCII characters.

Given a string input of Unicode characters, return a string with its characters in the reversed order of the input string.

In this challenge, the input string will be more than 7 bit ASCII characters and contain 8 bit Unicode characters (see this video for a great explanation of the differences between ASCII and Unicode).

If we use our initial function to reverse a string containing Unicode characters, we get weird and unexpected results. Let’s include an emoji in the string because, why not?!

function reverse(string) {
  return string.split('').reverse().join('')
}

reverse('JS is fun! 😄')
// => �� !nuf si SJ
Enter fullscreen mode Exit fullscreen mode

We can get around this by using the Array.from() method to create a new array from an array-like or iterable object (in our case a string).

function reverse(string) {
  return Array.from(str).reverse().join("")
}

reverse('JS is fun! 😄')
// => 😄 !nuf si SJ
Enter fullscreen mode Exit fullscreen mode

Conclusion

Now that you have learned about different ways to approach the reverse a string algorithm in JavaScript, take a look at:

For more reading, check out algorithm tutorials on Coderbyte and the sorting algorithms animations by Toptal.

I hope this was helpful! Let me know if you have any questions or comments. You can follow me on LinkedIn, GitHub, Twitter and on my website.

This article was originally published on anthonygharvey.com on July 28th, 2018

Top comments (5)

Collapse
 
qm3ster profile image
Mihail Malo • Edited

Yet another ridiculous approach (requires node.js):

const input = "Input string lol.\nNicely done haha.\nLook at it go!"
const buf = Buffer.from(input,'latin1')
for (let l = buf.length; l>0;l--){
  for (let i=0;i<l-1;i++){
    buf.slice(i,i+2).swap16();
  }
}
const output = buf.toString('latin1')
console.log(input)
console.log(output)

Among the reasons it is ridiculous is the fact that Buffers inherit .reverse() from Uint8Array, so I could just use that.

Or:

const rev = input => {
  const buf = Buffer.from(input,'latin1')
  const len = buf.length
  let j
  for (let i=len;i>0;i--)
    buf.slice(i%2,-(i+len)%2||j).swap16()
  return buf.toString('latin1')
}
Collapse
 
geocine profile image
Aivan Monceller

We could also use reduce.

function reverse(str){
  return [...str].reduce((rev, char)=> char + rev, ''); 
}
Collapse
 
anthonyharvey profile image
Anthony Harvey

Thanks for the feedback!

Collapse
 
ironydelerium profile image
ironydelerium

It's also worth noting that, in JavaScript anyway, you can't mutate a string: by the language definition itself, strings are immutable, as they're considered primitive values. Mutation only applies to objects (where you can change the object itself).

Collapse
 
sebvercammen profile image
Sébastien Vercammen • Edited

The reverse of a string, is that string traversed in reverse order.

Sounds obvious, but this is more efficient in languages that let you work with memory directly (swap a string's characters in place, or write the string to an output buffer in reverse).

Reasonable answers include their use cases and performance characteristics.

  • Benchmark for short strings
  • Benchmark for long strings
  • In use cases where the entire text doesn't need to be reversed at once (e.g. consuming the stream in real-time is more important than the fully reversed output), you may prefer to write a method that lazily yields letter by letter. It will have a slight overhead cost for each function call, but that's completely voided by the needs of your use case.

The recursive examples present a different problem: Most implementations don't support tail call optimization, so you might run into the upper limit of your call stack.

Everything also depends on JS implementation (e.g. different browsers). You may get different, maybe even opposite, results.

PS: These answers are valid today, but they might not be in the future. I've seen browser implementations change so often that the results jump from patch to patch. Don't expect anything in this thread to be a final answer, and instead learn to explain yourself and your thinking.