How to Concatenate Strings in an Array in JavaScript

How to Concatenate Strings in an Array in JavaScript

Data takes many forms - and lists are a very common one. Concatenating strings is a common task and there are several ways to go about it.

In the same way, concatenating strings in an array builds upon that task, for each string in that array. However, there's another very useful method we can use - the join() method which automates this process painlessly and seamlessly.

In this guide, we'll take a look at how to append all strings in an array, and then benchmark the performance of all the methods.

Array.prototype.join()

The easiest way to append all elements in an array into one is the join() method of the Array class. It joins all the elements into a string with the given optional delimiter.

If you omit the delimiter - it's set to a comma (,):

let platonicSolids = ['Tetrahedron', 'Cube', 'Octahedron', 'Dodecahedron', 'Icosahedron'];

let joinedWithDefaultDelimiter = platonicSolids.join();
let joinedWithDelimiter = platonicSolids.join('');
let joinedWithUnderscore = platonicSolids.join('_');
    
console.log(joinedWithDefaultDelimiter);
console.log(joinedWithDelimiter);
console.log(joinedWithUnderscore);

This results in:

Tetrahedron,Cube,Octahedron,Dodecahedron,Icosahedron
TetrahedronCubeOctahedronDodecahedronIcosahedron
Tetrahedron_Cube_Octahedron_Dodecahedron_Icosahedron

This is a great way of creating entries from objects for CSV files - let's define a simple object with a couple of fields and join() it into a CSV-formatted string:

const book = {genre:"Popular Science", name:"Our Mathematical Universe", author:"Max Tegmark"};

let csvString = Object.keys(book).map(field => book[field]).join();

console.log(csvString);

This way, we can easily convert a JavaScript object into a CSV-formatted string, with its field values being joined together:

Popular Science,Our Mathematical Universe,Max Tegmark

String.concat()

The concat() function is starightforward - it concats two strings. Given an array of entries, we can simply loop through it and concat() each entry onto an empty string and return it:

let platonicSolids = ['Tetrahedron', 'Cube', 'Octahedron', 'Dodecahedron', 'Icosahedron'];
let result = '';

for (let i = 0; i < platonicSolids.length; i++) {
    result = result.concat(platonicSolids[i]);
}

console.log(result);

Remember that strings are immutable and that we have to assign the result of the concat() operation back to a reference variable.

This results in:

TetrahedronCubeOctahedronDodecahedronIcosahedron

You can add in any delimiter here as well, simply by concatenating it in the loop with a check for the last element:

let platonicSolids = ['Tetrahedron', 'Cube', 'Octahedron', 'Dodecahedron', 'Icosahedron'];
let result = '';

for (let i = 0; i < platonicSolids.length; i++) {
    result = result.concat(platonicSolids[i]);
    if (i < platonicSolids.length - 1) {
        result = result.concat(",");
    }
}

console.log(result);

This results in:

Tetrahedron,Cube,Octahedron,Dodecahedron,Icosahedron

The + Operator

Naturally, if you can concat() strings together, you can also append them via the + operator:

let platonicSolids = ['Tetrahedron', 'Cube', 'Octahedron', 'Dodecahedron', 'Icosahedron'];
let result = '';

for (let i = 0; i < platonicSolids.length; i++) {
    result = result + platonicSolids[i];
}

console.log(result);

Or even better - you can use the shorthand += operator instead:

result += platonicSolids[i];

This also results in:

TetrahedronCubeOctahedronDodecahedronIcosahedron

Performance Benchmark

So, which approach is the best performance-wise? The join() method most definitely is the easiest one to use and looks the cleanest, but is it the most performant one for large corpora of elements?

Let's test these methods out and benchmark them.

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

First off, let's create a function that'll generate random strings for us:

function generateStrings(num) {
    let array = [];
    for (let i = 0; i < num; i++) {
        array.push((Math.random() + 1).toString(36).substring(2);
        }
        return array;
    }
}

The function generates a random number, converting it to a string with a radix of 36 and trims the leftover number at the start of the string with substring(). While this method has limitations for string generation - it'll work well enough for up to 50.000 elements and they will be fairly random up to that point.

Note: Keep in mind that this method is not cryptographically safe for random numbers, and that it's only being used for illustrational purposes, to get around the innate caching optimization we'd encounter while iterating many instances of the same string, to make sure that the benchmark is accurate.

Let's test it out:

let stringArray = generateStrings(5);
console.log(stringArray)

This results in:

[ 'e8e3mbqczk', '2wqjp9hko', 'szazekngkv', 'xsxl2bvh3w', 'd4vadxk9ny' ]

Awesome! Let's generate 25.000 strings and join them with our methods:

let stringArray = generateStrings(25000);

console.time('Concatenating with Operator');
let join1 = plusOperator(stringArray);
console.timeEnd('Concatenating with Operator');

console.time('Concatenating with concat()');
let join2 = concat(stringArray);
console.timeEnd('Concatenating with concat()');

console.time('Concatenating with join()');
let join3 = stringArray.join('');
console.timeEnd('Concatenating with join()');


function generateStrings(num) {
    let array = [];
    for (let i = 0; i < num; i++) {
        array.push((Math.random() + 1).toString(36).substring(2));
    }
    return array;
}

function plusOperator(array) {
    let result = '';
    for (let i = 0; i < array.length; i++) {
        result += array[i];
    }
    return result;
}

function concat(array) {
    let result = '';
    for (let i = 0; i < array.length; i++) {
        result = result.concat(array[i]);
    }
    return result;
}

Once they're generated and joined - these are the results:

Concatenating with Operator: 3.417ms
Concatenating with concat(): 2.879ms
Concatenating with join(): 8.930ms

If you're dealing with large numbers of data, the join() method is outperformed by custom implementations, to a large degree because of the innate delimiter logic. Even if you don't want to actually add a delimiter, you actually add an empty character, which takes additional time on large arrays.

If we were to add back the delimiters in our custom methods:

function plusOperator(array) {
    let result = '';
    for (let i = 0; i < array.length; i++) {
        result += array[i];
        if (i < array.length - 1) {
            result += ',';
        }
    }
    return result;
}

function concat(array) {
    let result = '';
    for (let i = 0; i < array.length; i++) {
        result = result.concat(array[i]);
        if (i < array.length - 1) {
            result = result.concat(',');
        }
    }
    return result;
}

Our results would be much different:

Concatenating with Operator: 3.914ms
Concatenating with concat(): 23.988ms
Concatenating with join(): 3.452ms

The operator performs a bit slower than the join() method, and the concat() method becomes really slow compared to both of these approaches.

It's also worth noting the official statement from MDN, regarding the performance benefits of concating strings with the concat() method or the operators is:

It is strongly recommended that the assignment operators (+, +=) are used instead of the concat() method.

However, this doesn't have to hold at all, and you can easily get concat() to outperform the + operator:

console.time('Concatenating with Operator');
concatWithOperator();
console.timeEnd('Concatenating with Operator');

console.time('Concatenating with Function');
concatWithFunction();
console.timeEnd('Concatenating with Function');

function concatWithOperator() {
    let result = "";
    for (let i = 0; i < 10000; i++) {
      result += i;
    }
}

function concatWithFunction() {
    let result = "";
    for (let i = 0; i < 10000; i++) {
      result = result.concat(i);
    }
}

This results in:

Concatenating with Operator: 1.921ms
Concatenating with Function: 0.855ms

Your browser, its version, as well as the optimizer it uses may vary from machine to machine, and properties like those really impact the performance.

Test and verify your own code instead of taking advice at face value. Not all machines and environments are the same, and what works great on one, might not work great on another.

Conclusion

In this guide, we've taken a detailed look into the different approaches to joining a list of strings into a single string, with and without delimiters.

We've taken a look at the common join() method, as well as implemented two methods of ours own to improve performance when delimiters aren't needed.

Finally, we've benchmarked them to compare their performance.

Last Updated: November 23rd, 2021
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

Want a remote job?

    Prepping for an interview?

    • Improve your skills by solving one coding problem every day
    • Get the solutions the next morning via email
    • Practice on actual problems asked by top companies, like:
     
     
     

    Getting Started with AWS in Node.js

    Build the foundation you'll need to provision, deploy, and run Node.js applications in the AWS cloud. Learn Lambda, EC2, S3, SQS, and more!

    © 2013-2021 Stack Abuse. All rights reserved.