Strings

Difficulty: Beginner

Strings are one of the most commonly used data types in JavaScript. A string is a sequence of characters used to represent text, enclosed in single quotes ('...'), double quotes ("..."), or backticks (`...`). JavaScript strings are immutable - once created, a string cannot be changed. Every string method that appears to modify a string actually returns a new string, leaving the original untouched.

Template literals (backtick strings) were introduced in ES6 and are a game-changer for string handling. They support embedded expressions via ${expression} syntax, multi-line strings without escape characters, and tagged templates for advanced use cases like syntax highlighting and internationalization. Template literals should be your default choice for any string that contains variables, expressions, or spans multiple lines.

JavaScript provides a rich set of built-in string methods for searching, extracting, and transforming text. Search methods include indexOf() (returns the position of a substring, or -1 if not found), includes() (returns a boolean), startsWith(), and endsWith(). Extraction methods include charAt() (single character at an index), slice() (extract a portion using start and end indices), and substring() (similar to slice but handles negative indices differently). The split() method divides a string into an array based on a delimiter.

Transformation methods include toUpperCase(), toLowerCase(), trim() (removes whitespace from both ends), trimStart(), trimEnd(), replace() (replaces the first match), replaceAll() (replaces all matches), repeat() (repeats a string N times), padStart(), and padEnd() (pads a string to a target length). The replace method accepts either a string or a regular expression as the search pattern, making it extremely powerful for text processing.

JavaScript strings are internally encoded as UTF-16. Most common characters (ASCII, Latin, Cyrillic) use a single 16-bit code unit, but many emoji and characters from other scripts use two code units (a surrogate pair). This means "smile".length might not equal the number of visible characters if the string contains emoji. The Array.from() function or the spread operator [...str] correctly splits strings by code points rather than code units, handling surrogate pairs properly.

Code examples

String Search Methods

const sentence = "JavaScript is a powerful programming language";

// Finding positions
console.log(sentence.indexOf("powerful"));      // 18
console.log(sentence.indexOf("Python"));        // -1
console.log(sentence.lastIndexOf("a"));         // 43

// Boolean checks
console.log(sentence.includes("powerful"));     // true
console.log(sentence.startsWith("JavaScript")); // true
console.log(sentence.endsWith("language"));     // true

// Searching from a position
console.log(sentence.indexOf("a", 5));  // 11 (first 'a' after index 5)
console.log(sentence.includes("is", 20)); // false ('is' not after index 20)

// charAt and bracket notation
console.log(sentence.charAt(0));    // "J"
console.log(sentence[0]);           // "J" (same as charAt)
console.log(sentence.charAt(100));  // "" (out of bounds)
console.log(sentence[100]);         // undefined (out of bounds)

indexOf returns the position or -1 if not found. includes, startsWith, and endsWith return booleans and are more readable for simple checks. charAt returns an empty string for out-of-bounds indices while bracket notation returns undefined.

Extracting and Splitting Strings

const str = "Hello, JavaScript World!";

// slice(start, end) - end is exclusive
console.log(str.slice(7, 17));    // "JavaScript"
console.log(str.slice(7));        // "JavaScript World!"
console.log(str.slice(-6));       // "orld!" (from end)

// substring(start, end) - similar to slice
console.log(str.substring(7, 17)); // "JavaScript"

// split - divide into array
const csv = "apple,banana,cherry,date";
console.log(csv.split(","));      // ["apple","banana","cherry","date"]
console.log(csv.split(",", 2));   // ["apple","banana"] (limit)

const words = "  hello   world  ".trim().split(/\s+/);
console.log(words);               // ["hello", "world"]

// split individual characters
console.log("Hello".split(""));   // ["H","e","l","l","o"]

slice is the preferred extraction method - it supports negative indices (counting from the end) and is more predictable than substring. split converts strings to arrays, which is essential for parsing CSV data, user input, and other text formats.

Transforming Strings

// Case conversion
console.log("Hello World".toUpperCase()); // "HELLO WORLD"
console.log("Hello World".toLowerCase()); // "hello world"

// Trimming whitespace
console.log("  hello  ".trim());      // "hello"
console.log("  hello  ".trimStart());  // "hello  "
console.log("  hello  ".trimEnd());    // "  hello"

// Replacing
console.log("hello world".replace("world", "JS")); // "hello JS"
console.log("aabbcc".replace("b", "X"));  // "aaXbcc" (first only)
console.log("aabbcc".replaceAll("b", "X")); // "aaXXcc" (all)

// Padding
console.log("5".padStart(3, "0"));   // "005"
console.log("5".padEnd(3, "."));     // "5.."
console.log("42".padStart(5));       // "   42" (default: space)

// Repeat
console.log("ha".repeat(3));         // "hahaha"
console.log("-".repeat(20));         // "--------------------"

All string methods return new strings - they never modify the original. replace only replaces the first occurrence; use replaceAll or a regex with the global flag for all occurrences. padStart is commonly used for formatting numbers with leading zeros.

Template Literals and String Immutability

// Template literals with expressions
const name = "Alice";
const age = 25;
console.log(`My name is ${name} and I am ${age} years old.`);
console.log(`Next year I'll be ${age + 1}.`);
console.log(`Is adult: ${age >= 18 ? "Yes" : "No"}`);

// Multi-line strings
const html = `
<div class="card">
  <h2>${name}</h2>
  <p>Age: ${age}</p>
</div>`;
console.log(html);

// String immutability
let greeting = "Hello";
greeting[0] = "J"; // Silently fails (no error, no change)
console.log(greeting); // "Hello" (unchanged)

// To "change" a string, create a new one
greeting = "J" + greeting.slice(1);
console.log(greeting); // "Jello"

// Chaining string methods
const cleaned = "  Hello, World!  "
  .trim()
  .toLowerCase()
  .replace("world", "javascript");
console.log(cleaned);

Template literals (backticks) support embedded expressions, multi-line text, and are the modern way to build strings. Strings are immutable - you cannot change individual characters. All string methods return new strings, so method chaining is a common and clean pattern.

Key points

Concepts covered

String Methods, Template Literals, String Immutability, Unicode, Search Methods, Transformation Methods