JavaScript strings are immutable — every method returns a new string. Once you know which method does what (and what returns what type), string manipulation becomes fast and readable. This cheat sheet covers every built-in string method, grouped by purpose, with code examples you can copy directly.
Quick-reference table
| Method | Returns | One-liner |
|---|---|---|
slice(start, end) |
string | Extract substring by index |
substring(start, end) |
string | Like slice but no negative index |
at(index) |
string | Supports negative index (at(-1) = last char) |
indexOf(str) |
number (-1 if not found) | First position of substring |
lastIndexOf(str) |
number | Last position of substring |
includes(str) |
boolean | Does string contain substring? |
startsWith(str) |
boolean | Does it start with this? |
endsWith(str) |
boolean | Does it end with this? |
split(sep) |
array | Break string into array |
join() |
string | Array method, opposite of split |
replace(pat, rep) |
string | Replace first match |
replaceAll(pat, rep) |
string | Replace all matches |
toUpperCase() |
string | All caps |
toLowerCase() |
string | All lower |
trim() |
string | Remove leading/trailing whitespace |
trimStart() |
string | Remove leading whitespace only |
trimEnd() |
string | Remove trailing whitespace only |
padStart(len, fill) |
string | Pad from left to target length |
padEnd(len, fill) |
string | Pad from right to target length |
repeat(n) |
string | Repeat the string n times |
concat(...strs) |
string | Concatenate (prefer template literals) |
charCodeAt(i) |
number | UTF-16 code unit at index |
codePointAt(i) |
number | Unicode code point (handles emoji) |
String.fromCharCode(n) |
string | Character from code unit |
String.fromCodePoint(n) |
string | Character from code point |
normalize(form) |
string | Unicode normalisation (NFC/NFD/NFKC/NFKD) |
match(regex) |
array/null | Find matches (first, or all with /g) |
matchAll(regex) |
iterator | All matches with capture groups (requires /g) |
search(regex) |
number | Index of first regex match |
localeCompare(str) |
number | Locale-aware comparison for sorting |
Extracting substrings
const s = "Hello, World!";
// slice — negative index counts from end
s.slice(7, 12); // "World"
s.slice(-6, -1); // "World"
s.slice(7); // "World!"
// at — the clean way to get last character
s.at(-1); // "!"
s.at(0); // "H"
// substring — like slice but clamps negative indexes to 0
s.substring(7, 12); // "World"
Use slice — it handles negative indexes and is more predictable.
Searching
const s = "the quick brown fox jumps over the lazy dog";
s.includes("fox"); // true
s.startsWith("the"); // true
s.endsWith("dog"); // true
s.indexOf("the"); // 0 (first occurrence)
s.lastIndexOf("the"); // 31 (last occurrence)
s.indexOf("cat"); // -1 (not found)
// Regex search — returns index or -1
s.search(/b\w+/); // 10 ("brown")
includes is cleaner than indexOf(x) !== -1 when you only need a boolean.
Replacing
const s = "I like cats. Cats are great.";
// replace — only first match (string pattern)
s.replace("cats", "dogs"); // "I like dogs. Cats are great."
// replaceAll — all matches (string pattern, case-sensitive)
s.replaceAll("cats", "dogs"); // "I like dogs. Cats are great."
// regex with /gi flag — case-insensitive, all matches
s.replace(/cats/gi, "dogs"); // "I like dogs. dogs are great."
// Capture groups
"2026-07-13".replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1");
// "13/07/2026"
// Function as replacement
"hello world".replace(/\b\w/g, c => c.toUpperCase());
// "Hello World"
Splitting and joining
// split
"a,b,c".split(","); // ["a", "b", "c"]
"hello".split(""); // ["h", "e", "l", "l", "o"]
"one two three".split(/\s+/); // ["one", "two", "three"]
// Limit
"a,b,c,d".split(",", 2); // ["a", "b"]
// The reverse is Array.prototype.join
["2026", "07", "13"].join("-"); // "2026-07-13"
Split on a regex when whitespace could be irregular.
Case conversion
"Hello World".toLowerCase(); // "hello world"
"Hello World".toUpperCase(); // "HELLO WORLD"
// Locale-aware (important for some languages)
"istanbul".toLocaleUpperCase("tr"); // "İSTANBUL" (dotted İ, Turkish)
"I".toLocaleLowerCase("tr"); // "ı" (dotless ı, Turkish)
Use toLocaleLowerCase / toLocaleUpperCase when the user's language matters.
Trimming and padding
// trim
" hello ".trim(); // "hello"
" hello ".trimStart(); // "hello "
" hello ".trimEnd(); // " hello"
// padStart / padEnd
"7".padStart(3, "0"); // "007"
"hi".padEnd(6, "."); // "hi...."
// Common use: zero-pad numbers
const h = 9, m = 5;
`${String(h).padStart(2,"0")}:${String(m).padStart(2,"0")}`; // "09:05"
Pattern matching with regex
const s = "Prices: $10.99, $4.50, $0.99";
// match with /g — returns array of matches or null
s.match(/\$[\d.]+/g); // ["$10.99", "$4.50", "$0.99"]
// matchAll — returns iterator with capture groups
const re = /\$(?<amount>[\d.]+)/g;
for (const m of s.matchAll(re)) {
console.log(m.groups.amount); // "10.99", "4.50", "0.99"
}
// Without /g, match returns details about the first match
"hello".match(/e(l+)o/);
// ["ello", "ll", index: 1, input: "hello", groups: undefined]
matchAll requires the /g flag; it throws without it.
Comparing and sorting
// Basic equality — always use === for strings
"hello" === "hello"; // true
// Locale-aware sort (handles accents, locale rules)
["Über", "apple", "Banana"].sort((a, b) => a.localeCompare(b));
// ["apple", "Banana", "Über"] (locale-specific order)
// Case-insensitive sort
["banana", "Apple", "cherry"].sort((a, b) =>
a.toLowerCase().localeCompare(b.toLowerCase())
);
// ["Apple", "banana", "cherry"]
Never sort strings with < / > — they compare by UTF-16 code unit, which breaks for accented characters.
Unicode and emoji
const emoji = "👍";
emoji.length; // 2 (surrogate pair — wrong!)
[...emoji].length; // 1 (correct — spread uses code points)
emoji.codePointAt(0); // 128077
// Iterating characters correctly
for (const char of "café") {
console.log(char); // c, a, f, é
}
// Normalisation — same visual character, different bytes
const a = "\u00e9"; // é (precomposed)
const b = "e\u0301"; // é (e + combining accent)
a === b; // false!
a.normalize() === b.normalize(); // true (both NFC after normalize)
Always spread ([...str]) or iterate with for...of when working with emoji or non-BMP characters.
6 common mistakes
1. Using length with emoji
// Wrong
"👍🏼".length; // 4 (surrogate pairs)
// Correct
[..."👍🏼"].length; // 2 (code points)
2. Forgetting that replace only hits the first match
"aaa".replace("a", "b"); // "baa" (only first!)
"aaa".replaceAll("a", "b"); // "bbb" (all)
"aaa".replace(/a/g, "b"); // "bbb" (regex with /g)
3. split("") breaks on emoji
"hi 👋".split(""); // ["h","i"," ","\uD83D","\uDC4B"] (broken!)
[..."hi 👋"]; // ["h","i"," ","👋"] (correct)
4. Mutating a "string" variable when you should be building
// Slow in a loop (creates a new string each iteration)
let s = "";
for (let i = 0; i < 10000; i++) s += "x";
// Better — collect in array, join once
const parts = [];
for (let i = 0; i < 10000; i++) parts.push("x");
const s = parts.join("");
5. Using > / < to compare strings
// Broken for anything beyond ASCII
"apple" < "Banana"; // false (uppercase B has lower code point)
// Correct
"apple".localeCompare("Banana") < 0; // true
6. Calling matchAll without /g
// Throws TypeError: String.prototype.matchAll called with a non-global RegExp
"abc".matchAll(/a/); // ❌
"abc".matchAll(/a/g); // ✅
6 FAQ
Q: What's the difference between slice and substring?slice accepts negative indexes (count from end); substring clamps them to 0. slice(-3) extracts the last three characters; substring(-3) returns the whole string. Prefer slice.
Q: How do I check if a string contains another string?
Use includes() for a boolean: s.includes("foo"). Use indexOf() if you need the position too: s.indexOf("foo") returns -1 when not found.
Q: How do I convert a number to a string with two decimal places?(3.14159).toFixed(2) returns "3.14". Note: toFixed rounds, and it returns a string, not a number. For currency, use Intl.NumberFormat instead to handle locale-specific decimal separators.
Q: How do I repeat a string n times?"ab".repeat(3) returns "ababab". Repeat(0) returns an empty string.
Q: What's the fastest way to reverse a string?[...str].reverse().join("") — spread first to handle multi-code-point characters (emoji). Avoid str.split("").reverse().join("") with emoji.
Q: How do I trim specific characters (not just whitespace)?
There's no built-in for arbitrary characters. Use replace with a regex:
// Trim slashes from both ends
"/path/to/resource/".replace(/^\/+|\/+$/g, ""); // "path/to/resource"
// Trim a specific character
"***hello***".replace(/^\*+|\*+$/g, ""); // "hello"
Related tools
Need to manipulate strings without writing code? Try these free tools:
- Case Converter — convert between camelCase, snake_case, PascalCase, kebab-case
- Reverse Text — reverse any string instantly
- Find and Replace — bulk find-and-replace in text
- Text Cleaner — remove extra whitespace, special characters, and more
- Slugify — convert any string to a URL-safe slug