- Published on
My Experiments with Reversing a String in JavaScript
- Authors

- Name
- Rakesh Tembhurne
- @tembhurnerakesh
There are many ways to do a simple thing in JavaScript, like reversing a string. The question is which one is the fastest.
So, I searched Google for the most common solutions and wrote a script to compare them. This article covers that script and what its output taught me.
How did I test?
I took inspiration from one or two scripts and then built my script for testing. The core function is as follows:
function test(repeats, description, func, expected) {
if (func() !== expected) {
console.info('\x1b[31m%s\x1b[0m', `${description}: Result not valid`)
return
}
const t1 = Date.now()
for (let i = 0; i < repeats; ++i) {
func()
}
const t2 = Date.now()
const dt = t2 - t1
console.log(`${description}: total time is ${dt} ms`)
results[description] = dt
}
The test function checks whether the output is correct. If it is, it runs the function many times and measures the time.
const results = {}
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args)
} else {
return function (...args2) {
return curried.apply(this, args.concat(args2))
}
}
}
}
const curriedTest = curry(test)
const repeatedTest = curriedTest(1_00_000)
Further, I made some changes to suit my needs. They're irrelevant to the topic here.
Functions To Reverse A String
Method 1: Split And Reverse
function arraySplitAndReverse(str) {
return str.split('').reverse().join('')
}
Method 2: Spread And Reverse
function arraySpreadAndReverse(str) {
return [...str].reverse().join('')
}
Method 3: Split And Reduce
function arraySplitAndReduce(str) {
return str.split('').reduce((x, y) => y.concat(x))
}
Method 4: Spread and Reduce
function arraySpreadAndReduce(str) {
return [...str].reduce((x, y) => y.concat(x))
}
Method 5: Straight 'for' Loop With String
function forLoopStraight(str) {
let reverse = ''
for (let i = 0; i < str.length; i++) {
reverse += str[str.length - 1 - i]
}
return reverse
}
Method 6: Inverse 'for' Loop With String
function forLoopInverse(str) {
let reverse = ''
for (let i = str.length - 1; i >= 0; i--) {
reverse += str[i]
}
return reverse
}
Method 7: Inverse 'for' Loop With Array
function forLoopInverseWithArray(str) {
const reverse = []
for (let i = str.length - 1; i >= 0; i--) {
reverse.push(str[i])
}
return reverse.join('')
}
Method 8: Swapping Indices With 'while' Loop
function reverseBySwappingIndices(str) {
const strArr = [...str]
let leftIndex = 0
let rightIndex = strArr.length - 1
while (leftIndex < rightIndex) {
let temp = strArr[leftIndex]
strArr[leftIndex] = strArr[rightIndex]
strArr[rightIndex] = temp
leftIndex++
rightIndex--
}
return strArr.join('')
}
Method 9: Swapping Indices With 'for' Loop
function divideAndConquer(str) {
const strArr = [...str]
let n = strArr.length - 1
for (let i = 0; i <= n / 2; i++) {
let temp = strArr[i]
strArr[i] = strArr[n - i]
strArr[n - i] = temp
}
return strArr.join('')
}
Method 10: Array Popping With 'while' Loop
function reverseWithWhileAndPop(str) {
const output = []
const strArr = [...str]
while (strArr.length) {
output.push(strArr.pop())
}
return output.join('')
}
Method 11: Array Map With Preserving Array
function mapPreservingArray(str) {
const strArr = [...str]
const reverse = strArr.map(strArr.pop, [...strArr])
return reverse.join('')
}
Method 12: Array Map Without Preserving Array
function mapWithoutPreservingArray(str) {
const strArr = [...str]
const reverse = [...strArr].map(strArr.pop, strArr)
return reverse.join('')
}
If you code, these snippets are self-explanatory. I tested each function 100,000 times.
// Test Functions
const testString =
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum"
const reverseString =
"muspI meroL fo snoisrev gnidulcni rekaMegaP sudlA ekil erawtfos gnihsilbup potksed htiw yltnecer erom dna ,segassap muspI meroL gniniatnoc steehs tesarteL fo esaeler eht htiw s0691 eht ni desiralupop saw tI .degnahcnu yllaitnesse gniniamer ,gnittesepyt cinortcele otni pael eht osla tub ,seirutnec evif ylno ton devivrus sah tI .koob nemiceps epyt a ekam ot ti delbmarcs dna epyt fo yellag a koot retnirp nwonknu na nehw ,s0051 eht ecnis reve txet ymmud dradnats s'yrtsudni eht neeb sah muspI meroL .yrtsudni gnittesepyt dna gnitnirp eht fo txet ymmud ylpmis si muspI meroL"
repeatedTest('split() and .reverse() method', () => arraySplitAndReverse(testString), reverseString)
repeatedTest(
'...spread and .reverse() method',
() => arraySpreadAndReverse(testString),
reverseString
)
repeatedTest('split() and .reduce() method', () => arraySplitAndReduce(testString), reverseString)
repeatedTest(
'...spread and .reduce() method',
() => arraySpreadAndReduce(testString),
reverseString
)
repeatedTest('For loop straight', () => forLoopStraight(testString), reverseString)
repeatedTest('For loop inverse', () => forLoopInverse(testString), reverseString)
repeatedTest(
'For loop inverse with Array',
() => forLoopInverseWithArray(testString),
reverseString
)
repeatedTest(
'Swapping Indices with temp variable',
() => reverseBySwappingIndices(testString),
reverseString
)
repeatedTest('Divide and conquer swapping', () => divideAndConquer(testString), reverseString)
repeatedTest('while loop and .pop()', () => reverseWithWhileAndPop(testString), reverseString)
repeatedTest('.map() preserving original', () => mapPreservingArray(testString), reverseString)
repeatedTest(
'.map() without preserving original',
() => mapWithoutPreservingArray(testString),
reverseString
)
The Result
Just to get comparative results, I wrote code to sort and add comparison in the form of 'slowness'.
let fastestTime = Infinity
const sortedResults = Object.entries(results)
.map(([desc, time]) => {
if (time < fastestTime) {
fastestTime = time
}
return {
desc,
time,
}
})
.map((result) => {
result.slowness = Number.parseFloat(result.time / fastestTime).toFixed(2) + 'x'
return result
})
.sort((a, b) => a.time - b.time)
console.table(sortedResults)

Conclusion
- Methods that skip arrays are the fastest, because they avoid converting strings to arrays and back.
.reduce()beat the built-in.reverse()on arrays in my runs..split("")beat...spreadfor converting a string into an array.- Working with indices cost comparatively more.