- 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. But the point is, how do you understand, what is the best or fastest way in all of them?
So, I made a quick search in Google, and found the most common solutions available, and made a script to compare them all. This article is all about that script and the lessons I learned from its output.
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, which calculates the time taken by the function to run repeatedly The function checks if the output we are getting is correct. And if that's fine, it will run the function multiple times and measure 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)
Futher, I made some modifications to suit my needs. They're irrelevant to the topic we are discussing 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 are a coder, the codes are self-explanatory. Now, its time to test these functions. I did test them each 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, where we don't need to use Arrays, are the fastest, obviously because we save time in converting strings to arrays and vice versa.
.reduce()
performed better than the built-in method.reverse()
to reverse an array..split("")
performed better than...spread
converting a string into an array.- Working with indices is a comparatively heavy operation.