Array.prototype.toString()
You rarely call it, and you invoke it constantly — every template literal, every string concatenation and every loose comparison against a string goes through here.
Demo
The output has no brackets and no quotes, which is the first surprise — an array does not stringify to anything resembling its literal form. The nested case is the important one: [1,[2,[3,4]]] becomes "1,2,3,4", because each element is itself converted to a string and nested arrays recurse all the way down. Nothing in the result tells you where one array ended and another began. null and undefined become empty strings, so two nulls produce a lone comma, and an object becomes the useless "[object Object]". If you want a representation you can read or parse back, you want JSON.stringify.
Common patterns
const csv = items.join(',');
const text = JSON.stringify(items);
const label = items.map(x => x ?? '-').join(', ');
Examples
Pitfalls
[1, [2, [3, 4]]].toString()
JSON.stringify([1, [2, [3, 4]]])
const key = 'user:' + [1, 2];
const key = 'user:' + items.join('-');
[null, undefined].toString()
[null, undefined].map(x => x ?? 'null').join(',')
[1, 2] == '1,2'
[1, 2] === '1,2'
[Symbol('x')].toString()
[Symbol('x')].map(String).join(',')
When to use
- Almost never directly — it runs implicitly on coercion
- A throwaway debug string for a flat array of primitives
- Understanding why an array appeared inside a string you built
- You want a specific separator → join
- You want to parse it back → JSON.stringify
- The array is nested → the structure is destroyed
- Elements may be null, undefined or objects → map them first
Notes
FAQ
None, except that join lets you pick the separator and toString is locked to a comma. toString is what runs when an array is coerced to a string, and calling join(',') explicitly produces exactly the same output — with the advantage that the next reader can see the separator.
[1, 2].toString(); // '1,2' [1, 2].join(','); // '1,2' [1, 2].join(' | '); // '1 | 2'