How to Concatenate JavaScript Strings
You have a greeting, a name and a punctuation mark. JavaScript can join all three, but the clearest tool depends on whether those pieces are individual values, expressions or an array.
To concatenate JavaScript strings, use
+for a few known pieces, a template literal for text containing values,join()for an array, andString.prototype.concat()when you specifically need a string method.
The Short Answer: Which Method Should You Use?
String concatenation means joining strings end to end to produce one new string. JavaScript strings are immutable, so concatenation does not extend an existing string in place. It calculates and returns another string.
Start with the smallest complete example:
const greeting = 'Hello, ' + 'Maya' + '.';
console.log(greeting); // Hello, Maya.
Hello, Maya.
The three operands appear in the result in the same order. Spaces and punctuation are ordinary characters, so the first piece includes a trailing space and the last contributes the period.
The selection rule follows the shape of the input:
- Use
+when you have a few known pieces. - Use a template literal when text contains variables or expressions.
- Use
join()when the pieces already live in an array. - Use
String.prototype.concat()when an API or coding constraint specifically calls for the method form.
These are not four interchangeable spellings. join() controls separators across a collection, while the other forms combine individually named values. The coercion rules also differ once an operand is not already a string.
If string syntax itself is unfamiliar, Strings covers quoting, escaping and string properties before these combinations become more involved.
Concatenate Strings With + and +=
The binary + operator joins two values when either value, after conversion to a primitive, is a string. You can chain the operator to join more pieces:
const firstName = 'Maya';
const action = 'saved';
const fileName = 'notes.js';
const message = firstName + ' ' + action + ' ' + fileName + '.';
console.log(message); // Maya saved notes.js.
Maya saved notes.js.
Each space belongs to a quoted string. Without those explicit spaces, the result would be Mayasavednotes.js. because concatenation does not insert separators.
When the value on the left is a string, += calculates a concatenated value and assigns it back to that variable. This standalone example builds one status line in stages:
let status = 'Build';
status += ': ';
status += 'passed';
status += ' in ';
status += 12;
status += ' seconds';
console.log(status); // Build: passed in 12 seconds
Build: passed in 12 seconds
The number 12 becomes the text 12 because the value on its left is already a string. The variable named status receives a new string after every assignment.
That conversion can obscure numeric addition. Say you want to add two counts before placing the total in a message:
const queued = 7;
const running = 5;
console.log('Jobs: ' + queued + running); // Jobs: 75
console.log('Jobs: ' + (queued + running)); // Jobs: 12
Jobs: 75
Jobs: 12
The first expression runs from left to right. 'Jobs: ' + queued produces the string 'Jobs: 7', then concatenating running adds the character 5. Parentheses make 7 + 5 happen while both operands are numbers.
This is the line to remember: perform arithmetic first, then concatenate its result. Type Conversions develops the conversion rules behind that change.
Insert Values With Template Literals
A template literal is a string enclosed by backticks. A ${expression} placeholder evaluates its expression, converts the result to a string and inserts it at that position.
Use one when a message contains named values:
const developer = 'Raj';
const openTasks = 4;
const message = `${developer} has ${openTasks} open tasks.`;
console.log(message); // Raj has 4 open tasks.
Raj has 4 open tasks.
The spaces and punctuation remain visible in the surrounding text. You do not need separate quoted operands for them, which makes template literals the default choice for readable messages containing dynamic values.
A placeholder accepts an expression, not only a variable:
const completed = 8;
const remaining = 3;
const report = `Completed: ${completed}
Remaining: ${remaining}
Total: ${completed + remaining}`;
console.log(report);
Completed: 8
Remaining: 3
Total: 11
The literal line breaks become part of report, and ${completed + remaining} performs numeric addition before inserting 11. No \n escape or parentheses around the addition are needed.
Backticks do not make the value safe for HTML. An ordinary template literal still produces a string, and assigning that string to innerHTML asks the browser to process it as markup. The safe sink for plain text is covered in the mistakes section.
Tagged templates use similar syntax but call a function with the literal parts and substitutions. They solve a different problem and are outside this concatenation rule.
Template literals also preserve the same underlying text model as quoted strings. Unicode, String internals explains why a visible character and a JavaScript string unit are not always the same thing.
Use String.prototype.concat() When You Need the Method
String.prototype.concat(...args) starts with its receiver, converts every argument directly to a string in order and returns the combined primitive string. It accepts one argument or many:
const prefix = 'Order ';
const orderNumber = 184;
const state = ' is ready';
const result = prefix.concat('#', orderNumber, state, '.');
console.log(result); // Order #184 is ready.
console.log(prefix); // Order
Order #184 is ready.
Order
The returned string contains all five pieces. prefix keeps its original value because strings cannot be mutated, so ignoring the return value also ignores the concatenation.
Calling concat() without arguments returns the receiver’s string value. It cannot create an observably separate copy because primitive strings have no mutable identity to copy.
String.prototype.concat() is unrelated to Array.prototype.concat(). The string method converts its arguments and produces a string; the array method combines array contents and produces an array. Similar name, different operation.
For ordinary application messages, + and template literals expose their structure more clearly. concat() earns its place when the method form is required, not because it changes the finished text.
Join an Array of Strings With join()
Array.prototype.join(separator) combines the elements of an array and places the separator between adjacent positions. It fits lists, generated fragments and other collections whose length may change.
Start with an array of labels:
const labels = ['draft', 'review', 'published'];
console.log(labels.join()); // draft,review,published
console.log(labels.join('')); // draftreviewpublished
console.log(labels.join(' ')); // draft review published
console.log(labels.join(' -> ')); // draft -> review -> published
draft,review,published
draftreviewpublished
draft review published
draft -> review -> published
Omitting the separator uses a comma. Passing '' inserts nothing, while ' ' inserts one space. The separator appears between elements, never after the last one.
A newline works as a separator too:
const steps = ['Install dependencies', 'Run tests', 'Create build'];
console.log(steps.join('\n'));
Install dependencies
Run tests
Create build
One join() handles every element without maintaining a separate accumulator. This is why it is the fixed choice when the input is already an array.
Empty arrays and missing-looking values need special attention:
console.log([].join('|')); //
console.log(['ready'].join('|')); // ready
console.log(['draft', null, undefined, , 'sent'].join('|')); // draft||||sent
ready
draft||||sent
The first printed line is empty because an empty array joins to ''. A one-element array needs no separator. In the last line, null, undefined and the empty slot each contribute an empty field, but their positions still produce separators.
That behavior makes join() useful for controlled separators, but it can also hide absent data. Validate or replace missing elements before joining when an empty field would be misleading. JavaScript Array Length: Count, Check, and Resize explains how empty slots differ from stored elements.
How Type Coercion Changes the Result
Type coercion is JavaScript converting a value from one type to another for an operation. The four concatenation forms do not begin that conversion in exactly the same way.
The + operator first converts both operands to primitive values. If either resulting primitive is a string, it converts the other to a string and concatenates. Otherwise, it performs numeric or BigInt addition according to the operand types.
Template interpolation and String.concat() perform direct string coercion. join() converts its elements too, except that null, undefined and empty slots become empty fields.
This table uses value in four expressions: '' + value, `${value}`, ''.concat(value) and [value].join('|').
value | + | Template | concat() | join() |
|---|---|---|---|---|
'draft' | draft | draft | draft | draft |
7 | 7 | 7 | 7 | 7 |
true | true | true | true | true |
null | null | null | null | empty string |
undefined | undefined | undefined | undefined | empty string |
[2, 3] | 2,3 | 2,3 | 2,3 | 2,3 |
{} | [object Object] | [object Object] | [object Object] | [object Object] |
7n | 7 | 7 | 7 | 7 |
Symbol('id') | throws TypeError | throws TypeError | throws TypeError | throws TypeError |
Here is the difference for the values that most often surprise you:
const values = [42, null, undefined, [2, 3], {}];
for (const value of values) {
console.log(
JSON.stringify({
plus: '' + value,
template: `${value}`,
concat: ''.concat(value),
join: [value].join('|'),
})
);
}
{"plus":"42","template":"42","concat":"42","join":"42"}
{"plus":"null","template":"null","concat":"null","join":""}
{"plus":"undefined","template":"undefined","concat":"undefined","join":""}
{"plus":"2,3","template":"2,3","concat":"2,3","join":"2,3"}
{"plus":"[object Object]","template":"[object Object]","concat":"[object Object]","join":"[object Object]"}
The null and undefined rows separate join() from the other forms. Arrays convert through their own textual representation, while an ordinary object commonly produces [object Object]. That object output identifies a conversion, not useful serialization. Use an intentional property or JSON methods, toJSON when you need structured data represented as text.
Primitive coercion gives + one further difference. An object can produce a number for + and text for direct string conversion:
const ticket = {
valueOf() {
return 40;
},
toString() {
return 'ticket';
},
};
console.log(ticket + 2); // 42
console.log(`${ticket}`); // ticket
console.log(''.concat(ticket)); // ticket
42
ticket
ticket
The first line receives the numeric primitive 40, so + performs addition. The other lines request a string directly and receive 'ticket'. Object to primitive conversion takes that decision sequence apart.
Symbols are an advanced boundary. Normal string coercion of a Symbol throws a TypeError, including in these four expressions. String(symbol) is the explicit exception and returns descriptive symbol text.
Common Concatenation Mistakes
Most concatenation bugs come from an invisible separator, an unexpected conversion or a returned value that went unused.
Missing spaces are characters that were never added:
const first = 'Maya';
const last = 'Chen';
console.log(first + last); // MayaChen
console.log(first + ' ' + last); // Maya Chen
console.log(`${first} ${last}`); // Maya Chen
MayaChen
Maya Chen
Maya Chen
Numeric operators need the same care. 'Score: ' + 8 + 2 produces 'Score: 82'; 'Score: ' + (8 + 2) produces 'Score: 10'. Decide whether the operation is arithmetic or text construction before writing the expression.
Immutable results must be assigned:
let label = 'Release';
label.concat(' candidate');
console.log(label); // Release
label = label.concat(' candidate');
console.log(label); // Release candidate
Release
Release candidate
The first concat() call calculates a value and discards it. The second stores the returned string.
With arrays, choose the separator explicitly. parts.join() inserts commas, while parts.join('') inserts nothing. Also inspect missing data before joining because null, undefined and sparse slots become empty fields.
[object Object] means an object reached string coercion without a useful textual form. Read the property you need, build a deliberate message, or serialize data as JSON. Do not treat the default object string as user-facing output.
Concatenation does not sanitize text. In a browser, place plain text into textContent:
const message = `Welcome, ${userSuppliedName}`;
const output = document.querySelector('[data-output]');
output.textContent = message;
This fragment prints nothing to the console. The browser displays the assembled message as text instead of processing it as HTML through innerHTML.
Performance does not change the selection rule. Universal rankings copied from old microbenchmarks do not describe every engine, input size or workload. Pick the method that matches the input, then profile the actual runtime if string construction appears in measured hot code.
The practical rule stays small: use + for a few pieces, template literals for messages containing values, join() for arrays, and concat() when you need that method. The JavaScript Fundamentals volume places these choices beside the string, array and conversion rules they depend on.
Frequently asked questions
What is the best way to concatenate strings in JavaScript?
+ for a few known string pieces and a template literal when values or expressions appear inside a message. Use join() for an array, and reserve String.prototype.concat() for code that specifically needs its method form.How do I concatenate a string and a number in JavaScript?
+ operator concatenates when either primitive operand is a string, so 'Total: ' + 12 produces 'Total: 12'. Put numeric addition in parentheses when it must happen first, as in 'Total: ' + (7 + 5).What is the difference between concat() and join() in JavaScript?
String.prototype.concat() appends arguments to one string and returns a new string. Array.prototype.join() combines array elements and inserts a chosen separator between them.Why does JavaScript join() omit null and undefined?
Array.prototype.join() treats null, undefined, and empty array slots as empty fields. Their positions still affect the separators, but the words null and undefined do not appear.Does concatenating text make it safe to use with innerHTML?
innerHTML. Assign plain text to textContent instead.