Skip to content

06 · Strings & Template Literals

🎥 Video walkthrough

String basics

const s = "Hello, World!";

console.log(s.toLowerCase());          // hello, world!
console.log(s.toUpperCase());          // HELLO, WORLD!
console.log(s.replace("World", "JS")); // Hello, JS!
console.log(s.split(", "));             // ['Hello', 'World!']
console.log(["a", "b", "c"].join(" ")); // a b c
console.log(s.trim());                  // removes leading/trailing whitespace
console.log(s.length);                  // 13
console.log(s.slice(7, 12));             // World

Template literals (preferred formatting method)

const name = "Ada";
const age = 30;
const pi = 3.14159265;

console.log(`${name} is ${age} years old`);
console.log(`pi rounded: ${pi.toFixed(2)}`); // pi rounded: 3.14
console.log(`${age.toString().padStart(5)}`); // right-pad in width 5
console.log(`${"x".repeat(3)}`);              // expressions work inside templates

function debugValue(label, value) {
  return `${label}=${JSON.stringify(value)}`; // there's no built-in `name=` shorthand like Python's f-string debug
}
console.log(debugValue("name", name)); // name="Ada"

Multi-line strings and template literal tags

const paragraph = `
This spans
multiple lines.
`;

// Template literals can also hold arbitrary expressions:
const items = ["a", "b", "c"];
console.log(`Items: ${items.map((i) => i.toUpperCase()).join(", ")}`);

Common string checks

"42".match(/^\d+$/) !== null; // true — digit check (see Level 2 · Module 6 for regex)
"hello".startsWith("he");     // true
"hello".endsWith("lo");        // true
"   ".trim().length === 0;      // true — whitespace-only check
"Hello, World!".includes("Hello"); // true — substring test

Immutability

Strings can't be modified in place — every "modification" returns a new string:

let str = "hello";
str.toUpperCase();       // returns "HELLO" but doesn't change str
str = str.toUpperCase();  // you must reassign to keep the result

Template literals cheat sheet

Need Syntax
Insert a variable `${value}`
Multi-line string `line1\nline2` or a literal newline inside backticks
Format a number value.toFixed(2), value.toLocaleString()
Pad a string str.padStart(n), str.padEnd(n)

How It Actually Works

Strings in V8 are immutable, but "immutable" doesn't mean "one representation." Short strings are stored inline as SeqOneByteString or SeqTwoByteString (depending on whether every character fits in Latin-1). Concatenating two strings with + or building one with a template literal doesn't necessarily copy all the characters immediately — V8 can create a ConsString, a lightweight object that just points at the two original strings and remembers their combined length. The actual character data is only flattened into one contiguous buffer the first time something needs to read it linearly (like calling .charAt() in a loop or passing it to a regex). This is why building large strings with many small += operations can look cheap per line but suddenly pay a large one-time flattening cost the first time you inspect the result.

Template literals (`${x}`) are handled specially by the parser: a tagged template like tag`a${b}c` is compiled so the same array of string parts (["a", "c"]) is passed to tag on every call at that call site — V8 caches and reuses that array object rather than rebuilding it, which is what lets libraries rely on referential identity of the strings array across calls to detect "this is the same literal template, just with different interpolated values."

🔀 See this in another language

Exercise

Write a function slugify(title) that converts "Hello, World! " into "hello-world" — lowercase, punctuation stripped, spaces replaced with hyphens.