JAVASCRIPT / STRINGS AND TEMPLATE LITERALS
Splitting and joining strings
Cut strings into arrays with split, rebuild them with join, and predict the piece counts, empty strings, and data loss that separators cause.
What you will learn
- Use split(sep) to get the pieces between separators; the separator itself is discarded.
- n separators always yield n+1 pieces, so an edge separator leaves an empty string.
- join(glue) puts glue only between neighbours, so one element comes back unchanged.
- Split on /\s+/ to collapse whitespace runs; split('') cuts UTF-16 units, not characters.
Understanding Splitting and joining strings
split answers a single question: what lies between the occurrences of this separator? It scans left to right, cuts at every match, and returns a new array holding the text between the cuts, so the separator characters never appear in the result. That framing explains the piece count (three commas always give four pieces) and why "/usr/local/".split("/") begins and ends with an empty string: there is genuinely nothing between the start of the string and the first slash. Strings are immutable, so the original is untouched and the pieces exist only if you keep the return value.
join runs the same idea backwards, from an array to a string. It converts each element to a string and inserts the glue between neighbouring elements, so k elements get k-1 pieces of glue and a one-element array comes back with no glue at all. Conversion uses the ordinary string rules with one surprise: null and undefined become empty strings rather than the words null and undefined, which is why a hole in your data shows up as a doubled separator instead of a visible marker. Calling join with no argument uses a comma, which is also what String(array) does.
For a plain string separator the two are exact inverses: text.split(sep).join(sep) reproduces text for any input. The extras break that identity, and it pays to know how. A regex separator such as /\s+/ lets one separator swallow a whole run of whitespace, which is what you want for tokenizing words but makes the original spacing unrecoverable; the optional second argument to split caps how many pieces you keep, so the tail is thrown away rather than bundled into the last piece; and split("") cuts between UTF-16 code units, which stops matching characters as soon as you leave the ASCII range.
const row = "2024-05-01,Ada Lovelace,engineer";
const fields = row.split(",");
console.log(fields.length);
console.log(fields[1]);
console.log(JSON.stringify(fields));
// join is the mirror image: it puts the glue back between the pieces
console.log(fields.join(" | "));
// a separator at the very edge leaves an empty piece behind
console.log(JSON.stringify("/usr/local/".split("/")));
// no argument means no cut at all: one piece, the whole string
console.log(JSON.stringify("a,b,c".split()));split and join trade between a string and the pieces that sit between its separators, and the separator always lives between neighbours, never around them.
Worked examples
Whitespace runs and the limit argument
Shows why a literal space is a poor separator for prose and what the second argument to split really does.
const sentence = "the quick brown\tfox";
console.log(JSON.stringify(sentence.split(" ")));
console.log(JSON.stringify(sentence.split(/\s+/)));
console.log(JSON.stringify("a-b-c-d".split("-", 2)));Example explained
Line 1split(" ") cuts at every single space, so three spaces in a row leave two empty pieces between them.
Line 2A tab is not a space, so brown and fox are never separated by the first call.
Line 3/\s+/ matches a whole run of spaces or tabs as one separator, which is the usual way to get words.
Line 4The 2 caps the number of pieces kept: c and d are discarded, not appended to b.
What join does with awkward arrays
Demonstrates how join converts elements and where the glue does and does not appear.
const parts = ["shopping", null, "list", undefined, ""];
console.log(parts.join("-"));
console.log(["one"].join(" and "));
console.log(["a", "b", "c"].join(""));
console.log(JSON.stringify([].join(",")));
console.log([1, 2, 3].join());Example explained
Line 1null and undefined turn into empty strings, so you see doubled dashes instead of shopping-null-list.
Line 2Glue sits between neighbours only, so a single element is returned untouched and " and " never appears.
Line 3An empty array joins to the empty string; JSON.stringify makes that invisible result visible as "".
Line 4With no argument join uses a comma and converts the numbers with the standard string conversion.
Round trips and the split("") trap
Uses split with an array method and join to transform text, then shows where per-character splitting breaks.
console.log("one two three".split(" ").reverse().join(" "));
console.log("stressed".split("").reverse().join(""));
console.log("ab😀".split("").length);
console.log(JSON.stringify("ab😀".split("")));
console.log([..."ab😀"].length);Example explained
Line 1split gets you into array land, reverse is an array method, and join gets you back out; the original string is never mutated.
Line 2split("") produces one entry per UTF-16 code unit, which is harmless for plain ASCII like stressed.
Line 3The emoji is a surrogate pair, so split("") reports 4 pieces and tears it into two halves that mean nothing alone.
Line 4Spreading a string iterates code points instead, keeping the emoji whole and reporting 3.
Important notes
split("") iterates UTF-16 code units, so emoji and other astral characters break in half; use [...str] or Array.from(str) for code points, and Intl.Segmenter for grapheme clusters such as flags and skin-tone sequences.
A capturing group in a regex separator injects the captured text into the array: "a1b".split(/(\d)/) gives ["a","1","b"], so use a non-capturing group (?:...) when you only want to group.
Common mistakes
Calling row.split(",") without storing the result: the string is immutable, so nothing changes and the array of pieces is thrown away immediately.
Expecting the limit argument to keep the remainder, as in "key=a=b".split("=", 2), which gives ["key","a"] and silently loses =b; use indexOf plus slice when you want the rest of the string.
Mixing up which type owns which method: calling .join on a string, or .split on an array, throws a TypeError saying the function does not exist, because split belongs to strings and join belongs to arrays.
Try it yourself
Change, predict, then run
Start from the string " red , green ,, blue " and produce exactly ["red","green","blue"] with no padded or empty entries, then print it as red > green > blue using a single join call.
Open the JavaScript workspaceCheck your understanding
What does "a,b,c".split(",", 2).join(",") evaluate to?
- "a,b,c"
- "a,bc"
- "a,b"
- "a,b,"
Show answer
The limit caps the array at two pieces, ["a","b"], and "c" is discarded rather than merged into the last piece, so joining gives "a,b". "a,b,c" is tempting because the round trip split(sep).join(sep) does restore the original, but only when no limit is passed; with a limit the discarded tail is gone for good.