JavaScript: Strings

Master string creation, template literals, escape characters, immutability, and every essential string method.

String Creation

Strings can be created as primitives using literals (the standard approach) or as objects using the String constructor. Always use literals, the constructor creates an object, not a primitive, which causes unexpected behaviour with equality checks.

String Literals vs Constructor

Three quote styles for literals, backticks are the most powerful.

  • Optional start position: str.indexOf("l", 4), search from index 4
  • Backticks `...`: template literals, support interpolation and multi-line
  • lastIndexOf() finds the last match, useful for file paths and URLs
  • String(42) (no new) converts a value to a primitive string, this is fine

String Creation

Always use literals. String() for conversion is fine, new String() is not.

Template Literals

Template literals use backticks and unlock two powerful features: embedded expressions via ${} and genuine multi-line strings without escape sequences.

Template Literals

Backtick strings replace concatenation and make multi-line strings natural.

  • Embed any expression: `Total: ${"{price * qty}"}`
  • Multi-line: press Enter inside backticks, no \n needed
  • Tagged templates: a function can process the template (advanced)
  • Nested backticks must be escaped: \`

Template Literals vs Concatenation

Any valid JavaScript expression goes inside ${}, including ternaries and function calls.

Escape Characters

Escape sequences let you include special characters inside a string that would otherwise be impossible or ambiguous to write directly.

Escape Sequences

A backslash tells the parser to treat the next character specially.

  • \n: newline
  • \t: tab
  • \\: literal backslash
  • \": double quote inside double-quoted string
  • \': single quote inside single-quoted string
  • \`: backtick inside template literal
  • \u0041: Unicode escape → "A"

Escape Sequences

\\n and \\t are the most common, use template literals to avoid most escaping.

String Properties: length

The length property returns the number of UTF-16 code units in a string. For most characters this equals the number of visible characters, with some exceptions for emoji and surrogate pairs.

.length

The only built-in property on strings, everything else is a method.

  • Read-only: you cannot set length to truncate a string
  • Empty string "" has length 0
  • Spaces count: "hi there".length === 8
  • Last character index is always length - 1

.length Property

length - 1 is always the index of the last character.

charAt() and charCodeAt()

charAt(i) returns the character at index i. charCodeAt(i) returns its UTF-16 numeric code. Both are useful when iterating over characters or doing character-level comparisons.

charAt() / charCodeAt()

Access individual characters by index or get their numeric character codes.

  • charAt(i): same as bracket notation str[i] but returns "" for out-of-range (bracket gives undefined)
  • charCodeAt(i): UTF-16 code of the character at index i
  • String.fromCharCode(65): reverse: code → character ("A")

charAt and charCodeAt

charCodeAt is useful for sorting algorithms and character-level validation.

concat()

concat() joins two or more strings and returns a new string. In practice, template literals or the + operator are preferred for readability.

concat()

Joins strings, functionally the same as + but more verbose.

  • Accepts multiple arguments: "a".concat("b", "c")"abc"
  • Returns a new string, the originals are untouched
  • Template literals are almost always cleaner for real use cases

concat()

Prefer template literals over concat, same result, easier to read.

indexOf() and lastIndexOf()

indexOf() returns the index of the first occurrence of a substring. lastIndexOf() searches from the end. Both return -1 if not found.

indexOf() / lastIndexOf()

Find the position of a substring, returns -1 when not found.

  • Case-sensitive: "Hello".indexOf("h") returns -1
  • Optional start position: str.indexOf("l", 4), search from index 4
  • Check for existence: str.indexOf("x") !== -1 (or use includes())
  • lastIndexOf() finds the last match, useful for file paths and URLs

indexOf and lastIndexOf

Use includes() for a simple existence check, indexOf when you need the position.

slice(), substring(), and substr()

All three extract a portion of a string. slice() is the modern standard, it supports negative indices. substr() is deprecated.

slice() vs substring()

Use slice(), it handles negative indices and is the community standard.

  • slice(start, end): end is exclusive; negative indices count from the end
  • substring(start, end): no negative indices; swaps args if start > end
  • substr(start, length): deprecated, second arg is length not end index
  • None of them mutate the original string

slice vs substring vs substr

slice(-6) counts 6 back from the end, negative indices make slice the clear winner.

toLowerCase() and toUpperCase()

These methods return a new string with all characters converted to lower or upper case. They are commonly used to normalise user input before comparisons.

Case Conversion

Normalise case before comparing strings to avoid case-sensitivity bugs.

  • Returns a new string, original is unchanged
  • Use for case-insensitive comparisons: a.toLowerCase() === b.toLowerCase()
  • Works with all Unicode characters

Case Conversion

Always normalise case before comparing user-provided strings.

trim(), trimStart(), and trimEnd()

These methods remove whitespace (spaces, tabs, newlines) from the edges of a string. Essential for sanitising user input from forms.

trim Methods

Strip leading and/or trailing whitespace, always trim user input before processing.

  • trim(): removes whitespace from both ends
  • trimStart(): removes from the start (left) only
  • trimEnd(): removes from the end (right) only
  • Does not affect whitespace inside the string

trim, trimStart, trimEnd

Always trim() user input before validation or storage.

split(), replace(), and replaceAll()

split() breaks a string into an array. replace() swaps the first match. replaceAll() swaps every match.

split / replace / replaceAll

The core trio for transforming string content.

  • split(separator) → array; split("") splits into individual characters
  • replace(search, replacement): replaces only the first match
  • replaceAll(search, replacement): replaces all matches
  • Both replace methods accept regex as the search argument

split, replace, replaceAll

replace only hits the first match, use replaceAll when you want every occurrence.

includes(), startsWith(), and endsWith()

These three ES6 methods return booleans and replace the older indexOf() !== -1 pattern with readable, intent-revealing code.

includes / startsWith / endsWith

Readable boolean checks, prefer these over indexOf for existence testing.

  • includes(sub): true if sub appears anywhere
  • startsWith(sub): true if string begins with sub
  • endsWith(sub): true if string ends with sub
  • All are case-sensitive; all accept an optional position argument

includes, startsWith, endsWith

url.startsWith('https') reads like plain English, that is the point.

repeat(), padStart(), and padEnd()

repeat() duplicates a string n times. padStart() and padEnd() pad a string to a target length, useful for formatting numbers and IDs.

repeat / padStart / padEnd

Utility methods for generating and formatting string output.

  • repeat(n): returns the string repeated n times
  • padStart(length, char): pads from the left until total length is reached
  • padEnd(length, char): pads from the right
  • Default pad character is a space if omitted

repeat, padStart, padEnd

padStart('0') is the standard way to zero-pad numeric IDs and codes.

Multi-line Strings

Template literals make multi-line strings natural, just press Enter. With single or double quotes you must use \n escape sequences or line continuation with a backslash.

Multi-line Strings

Template literals are the clean, modern way to write multi-line string content.

  • Template literal: just press Enter inside backticks
  • Old way with quotes: append \n or use string concatenation across lines
  • Indentation inside the template literal is part of the string
  • Useful for HTML snippets, SQL queries, or long messages in code

Multi-line Strings

Template literals preserve actual line breaks, no \\n needed.

String Immutability

Strings are immutable in JavaScript, you cannot change an individual character in place. Every string method returns a new string; the original is never modified.

Immutability

No string method modifies the original, always capture the return value.

  • Bracket assignment str[0] = "X" silently does nothing
  • Methods like toUpperCase(), replace(), trim() all return new strings
  • A common bug: calling a method and not capturing the result
  • Immutability makes strings safe to share, no defensive copying needed

String Immutability

The #1 string bug: calling a method and forgetting to save the returned value.

Knowledge Check

1. Which quote style supports multi-line strings and interpolation natively?

2. What does "hello".slice(1, 3) return?

3. What does " hello ".trim() return?

4. Which method checks if a string contains a substring?

5. What is string immutability?

6. What does "abc".padStart(5, "0") return?

7. What does "a,b,c".split(",") return?

8. What escape sequence produces a newline in a string?