Cheatsheet

JavaScript String Methods Cheatsheet

This sheet lists the methods on String.prototype that you use most, with what each returns and what happens on a miss. It is for developers who mix up slice, substring and substr, or who get surprised by emoji lengths and replace only changing the first match. The confusion it clears up: strings are immutable, so every method returns a new value, and lengths count UTF-16 code units, not visible characters.

Quick reference

Read and slice

Method Returns Notes
`s.length` Number of UTF-16 code units A property, not a method
`s[i]`, `s.charAt(i)` One code unit Out of range: `undefined` and `''`
`s.at(i)` One code unit Negative counts from the end
`s.slice(start, end)` Substring Negative indexes count from the end
`s.substring(start, end)` Substring Negatives become 0, swaps if start is larger
`s.substr(start, length)` Substring Legacy Annex B feature, avoid it
`s.codePointAt(i)` Code point number `'😀'.codePointAt(0)` is `128512`
`s.charCodeAt(i)` UTF-16 code unit `'😀'.charCodeAt(0)` is `55357`

Search and test

Method Returns Not found
`indexOf(text, from)` First index `-1`
`lastIndexOf(text, from)` Last index `-1`
`includes(text, from)` boolean `false`
`startsWith(text, pos)` boolean `false`
`endsWith(text, len)` boolean `false`
`search(regex)` Index of first match `-1`
`match(regex)` Array, or all matches with `g` `null`
`matchAll(regex)` Iterator of match objects, needs `g` empty iterator

Change and build

Method Returns
`replace(pattern, replacement)` New string, first match only when the pattern is a string
`replaceAll(pattern, replacement)` New string, every match
`toUpperCase()`, `toLowerCase()` Case-changed copy
`trim()`, `trimStart()`, `trimEnd()` Whitespace removed
`padStart(length, fill)`, `padEnd(length, fill)` Padded to a target length
`repeat(count)` Concatenated copies
`concat(...parts)` Joined string, `+` and template literals are usual
`split(separator, limit)` Array of pieces
`normalize(form)` Unicode-normalized string, default `NFC`
`localeCompare(other, locales, options)` Negative, 0 or positive
`isWellFormed()`, `toWellFormed()` Lone-surrogate check and repair

Replacement patterns

Token Inserts
`$$` A literal `$`
`$&` The matched text
`$1` to `$99` A numbered capture group
`` $` `` Text before the match
`$'` Text after the match
`$<name>` A named capture group

When newer methods became widely available

Method Available across browsers since
`trim`, `split` July 2015
`normalize` September 2016
`padStart`, `padEnd` April 2017
`matchAll` January 2020
`replaceAll` August 2020
`at` March 2022
`isWellFormed`, `toWellFormed` October 2023

Dates come from MDN's Baseline notes. Check your own browser support policy before relying on the newest methods.

Common patterns

Slice from either end

const s = 'Hello, World';
console.log(s.slice(-5), s.slice(0, 5), s.slice(7, -1));
console.log(s.substring(5, 0), s.substring(-3, 5), s.slice(5, 0) === '');
World Hello Worl
Hello Hello true

slice takes negative numbers literally as offsets from the end and returns '' if start is past end. substring swaps its arguments and clamps negatives to 0, which hides mistakes. Prefer slice.

Replace every match

console.log('a-b-c'.replace('-', '+'));
console.log('a-b-c'.replaceAll('-', '+'));
console.log('John Smith'.replace(/(\w+) (\w+)/, '$2, $1'));
console.log('abc'.replace(/b/, m => m.toUpperCase()));
a+b-c
a+b+c
Smith, John
aBc

A string pattern replaces only the first match. replaceAll replaces all, and a function replacement receives the match and its groups.

Zero-pad and align

console.log('5'.padStart(3, '0'), 'ab'.padEnd(5, '-') + '|', '12345'.padStart(3, '0'));
console.log('x'.padStart(5, 'ab'));
005 ab---| 12345
ababx

Padding never truncates, so a longer string comes back unchanged. The fill string repeats and is cut to fit.

Split, with and without a limit

console.log('a,b,,c'.split(','), 'a,b,c'.split(',', 2));
console.log('a1b2'.split(/\d/), 'a1b2'.split(/(\d)/));
console.log(''.split(','), ''.split(''));
[ 'a', 'b', '', 'c' ] [ 'a', 'b' ]
[ 'a', 'b', '' ] [ 'a', '1', 'b', '2', '' ]
[ '' ] []

Consecutive separators produce empty strings. Capture groups in a regex separator are kept in the result. An empty string split by a comma gives [''], not [].

Find all matches with positions

console.log([...'a1b22c333'.matchAll(/\d+/g)].map(m => [m[0], m.index]));
console.log('abc'.match(/(?<first>a)/).groups.first);
[ [ '1', 1 ], [ '22', 3 ], [ '333', 6 ] ]
a

matchAll gives every match with its index and groups, where match with g gives only the strings. Try patterns in the Regex Tester.

Compare and sort text

console.log('a'.localeCompare('B'), 'a' < 'B');
console.log(['10', '9', '2'].sort());
console.log(['10', '9', '2'].sort((a, b) => a.localeCompare(b, undefined, {numeric: true})));
console.log('ä'.localeCompare('z', 'de'), 'ä'.localeCompare('z', 'sv'));
-1 false
[ '10', '2', '9' ]
[ '2', '9', '10' ]
-1 1

The < operator compares code units, so 'B' sorts before 'a'. localeCompare follows the language, and in Swedish ä sorts after z.

Capitalize and reformat

console.log('hello world'.replace(/\b\w/g, c => c.toUpperCase()));
console.log('camelCaseString'.replace(/([A-Z])/g, ' $1').toLowerCase());
console.log('tEsT'.charAt(0).toUpperCase() + 'tEsT'.slice(1).toLowerCase());
Hello World
camel case string
Test

For more naming styles, the Case Converter handles camelCase, snake_case and Title Case.

Make a URL slug and shorten text

const slug = s => s.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().trim()
  .replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
console.log(slug('  Crème Brûlée & Café!  '));
const trunc = (s, n) => s.length > n ? s.slice(0, n - 1) + '…' : s;
console.log(trunc('JavaScript strings', 10));
creme-brulee-cafe
JavaScrip…

normalize('NFD') splits accented letters into a base letter plus a combining mark, and the first regex strips the marks. The truncation counts code units, so it can cut an emoji in half. Use Array.from(s).slice(0, n) if the text may hold emoji.

Pitfalls

  • Emoji length: '😀'.length is 2 and [...'😀'].length is 1, because indexing and length use UTF-16 code units. Spread or Array.from to count code points. Even that splits some emoji sequences and combining marks.
  • Reversing with split(''): 'a😀b'.split('').reverse().join('') breaks the emoji into two halves, while [...'a😀b'].reverse().join('') gives b😀a.
  • Visually equal strings that differ: 'é' is 1 code unit and 'é' is 2, so 'é' === 'é' is false. Call normalize() on both sides before comparing.
  • replaceAll with a non-global regex: 'a-b'.replaceAll(/-/, '+') throws TypeError: String.prototype.replaceAll called with a non-global RegExp argument. Add the g flag or use a string.
  • Special tokens in the replacement: 'abc'.replace('b', '$&$&') gives abbc, and 'x'.replace('x', '$$') gives $. When inserting user text, pass a function: s.replace(x, () => userText).
  • Expecting mutation: t[0] = 'X' on a string does nothing in sloppy mode, and in strict mode throws Cannot assign to read only property '0' of string 'abc'. Assign the result of the method back to a variable.
  • Case mapping is not one to one: 'ß'.toUpperCase() is 'SS', and 'İ'.toLowerCase().length is 2. Do not assume the length is unchanged, and use localeCompare with sensitivity: 'base' for caseless comparison.
  • substr and argument order: substr(start, length) takes a length where slice(start, end) takes an end index. MDN calls substr an Annex B feature and advises slice or substring instead.
  • split(',') on empty input: it returns [''] with one item, so a loop over the result runs once. Filter empties or check the input first.
  • Loose equality with String objects: 'abc' == new String('abc') is true, but typeof new String('abc') is object. Avoid the new String constructor.

Related ZipKit tools

  • Case Converter — converts text between camelCase, snake_case, Title Case and other formats
  • Reverse String — reverses text, words or lines
  • Word Counter & Text Statistics — counts words, characters, sentences and paragraphs
  • Regex Tester — try the patterns you pass to match, replace and split
  • Text Repeater — repeats text with a separator, like repeat() with a custom joiner

Related cheatsheets