# String concat in JavaScript Performance Comparison

JavaScript offers several ways to concatenate strings. Let’s learn how to concatenate strings and which one is the best performance.

## Plus Operator and Template Strings/Literal (backtick/backquote)

Using the plus operator to concatenate strings is supported by many languages. We can put variables into a statement without plus operator by using “”. It is called Template Literal which was called Template String before.

const str1 = "Hello";
const str2 = "I'm";
const str3 = "Yuto";

const msg = str1 + "," + str2 + " " + str3;
const msg2 = ${str1},${str2} ${str3}; const msg3 = str1.concat(str2, str3); console.log(msg); // Hello,I'm Yuto console.log(msg2); // Hello, I'm Yuto ## Template Literal is not readable Template Literal is useful because we can put everything in the same statement. However, it gets a bit unreadable when the variable names are long. const longKeywordVariable = "key"; const longKeywordNumber = 12 const longKeywordValue = "value"; const msg = ${longKeywordVariable}-${longKeywordNumber}-${longKeywordValue};
console.log(msg);
// key-12-value

We may need to scroll to see what values are used. The first improvement is the following.

const msg2 = ${longKeywordVariable}-${longKeywordNumber}-
${longKeywordValue}; It’s more readable than before but it doesn’t work as expected. The result is the following. // key- // 12- // value Since it is the same statement and each variable is written on a new line. It needs to be separated as follows. const msg3 = ${longKeywordVariable}-
+ ${longKeywordNumber}- + ${longKeywordValue};
console.log(msg3);
// key-12-value

Furthermore, using Array.prototype.join function is better when the variables are concatenated with the same string.

const msg4 = [
longKeywordVariable,
longKeywordNumber,
longKeywordValue,
].join("-");
console.log(msg4);
// key-12-value

## Performance comparison concat vs Template Literal vs Array.join

I measured the performance difference. The common function is the following.

import { performance } from "perf_hooks";

function doLoop(cb: () => void) {
for (let i = 0; i < 1000000; i++) {
cb();
}
}

type TestDataType = { startStr: string, copiedStr: string };
const copiedStr = "x".repeat(100);

function measure(title: string, cb: (args: TestDataType) => void) {
const start = performance.now();
const args = { startStr: "", copiedStr };
cb(args);
const result = performance.now() - start;
console.log(result(${title}):${Math.round(result)} ms);
}

What we need to do is to define the callback function and set it to cb. I defined the following functions.

const runConcat = () => measure("concat with", (args: TestDataType) => {
const cb = () => {
args.startStr = args.startStr.concat(args.copiedStr);
}
doLoop(cb);
});
const runPlus = () => measure("+ operator", (args: TestDataType) => {
const cb = () => { args.startStr += args.copiedStr };
doLoop(cb);
});
const runLiteral = () => measure("Template Literal", (args: TestDataType) => {
const cb = () => {
args.startStr = ${args.startStr}${args.copiedStr};
};
doLoop(cb);
});
const runJoin = () => measure("Array.join with loop", () => {
const result: string[] = [];
doLoop(() => {
result.push(copiedStr);
});
result.join("");
});

const runReduce = () => measure("Array.reduce with loop", () => {
const result: string[] = [];
doLoop(() => {
result.push(copiedStr);
});
result.reduce((pre, cur) => pre + cur);
});

// ------ without loop -------

const array: string[] = [];
doLoop(() => {
array.push(copiedStr);
});

const runJoinWithout = () => measure("Array.join without loop", () => array.join(""));

const runReduceWithout = () => measure("Array.reduce without loop", () => {
array.reduce((pre, cur) => pre + cur);
});

for (let i = 0; i < 10; i++) {
runConcat();
// runLiteral();
// runPlus();
// runJoin();
// runJoinWithout();
// runReduce();
// runReduceWithout();
}

The last for loop is the statement for the main process. I executed only one function at a time so that I could measure without side effects. This is the result including for-loop.

This result doesn’t include for-loop which means using the array directly.

The compiler couldn’t build the following code because the number of arrays is too big to put the argument.

const runConcatWithout = () => {
measure("concat without loop", (args: TestDataType) => {
args.startStr.concat(...array);
});
}
// RangeError: Maximum call stack size exceeded

By the way, the versions when I measured this is the following.

$tsc -v Version 4.0.3$ node -v
v14.13.0

## Summary

Array.prototype.join` function is the slowest to concatenate string. Others are almost the same performance. In most cases, we don’t have to take care of which one to use. Its difference is very small even though the string is long.

Technical Feeder