Strings, Templates and Text

Strings are immutable UTF-16 sequences with a rich method set. This lesson covers day-to-day text handling and the Unicode traps that bite emoji and non-Latin scripts.

Strings are immutable

Quoting and escaping

Write strings in single quotes, double quotes or backticks — pick one style and keep it. To put a quote inside a like quote, escape it with a backslash:

const single = 'She said "hi"';    // mixed quotes need no escaping
const escaped = "She said \"hi\"";  // same string, escaped
const template = `She said "hi"`;  // backticks: the modern default (below)

Methods return new strings

let name = "ada";
name.toUpperCase();        // produces "ADA"...
console.log(name);         // "ada" — the original is UNCHANGED
name = name.toUpperCase(); // ...so you store the result back
console.log(name);         // "ADA"

If you get this instead: the original text — you called a method and dropped the result. Strings cannot be modified; every string method is a factory for a new string.

The everyday methods

Measure, search, cut, clean

const file = "report-2026.pdf";
console.log(file.length);            // 13 — characters (careful: see Unicode below)
console.log(file.includes("2026"));  // true
console.log(file.startsWith("re"));  // true
console.log(file.slice(7, 11));      // "2026" — start included, end excluded
console.log(file.slice(-4));         // ".pdf" — negative counts from the end
console.log("  hi  ".trim());        // "hi"
console.log("a,b,c".split(","));     // [ 'a', 'b', 'c' ] — an array now
console.log("7".padStart(3, "0"));   // "007" — fixed-width numbers

replace and replaceAll

console.log("2026-05-01".replaceAll("-", "/")); // "2026/05/01"
console.log("aaa".replace("a", "b"));           // "baa" — replace changes ONE

Template literals

Interpolation: values inside text

Backtick strings embed any expression with ${...} — no more quote-juggling arithmetic:

const user = "Ada";
const score = 98;
console.log(`${user} scored ${score}% (${score >= 90 ? "pass" : "retry"})`);
// -> Ada scored 98% (pass)

Anything inside ${} is a full expression: arithmetic, comparisons, function calls. Multi-line text comes free — press Enter inside a backtick string and the newline belongs to the string.

Characters: code units versus code points

The emoji contraexample

const thumbs = "👍";
console.log(thumbs.length);      // 2  (!) — stored as TWO UTF-16 code units
console.log(thumbs[0]);          // half an emoji — a garbage character
console.log([...thumbs].length); // 1 — spread iterates real characters

Strings are sequences of UTF-16 code units, and characters outside the basic range (emoji, rare scripts) take two units; indexing with [0] cuts them in half. The rule: iterate with for...of or [...str] when real characters matter — use length for storage size, never for "how many letters".

Numbers to text and back

Converting at the edges

console.log(String(42));            // "42"
console.log(Number("42.5"));        // 42.5 — strict; garbage in, NaN out
console.log((1234.567).toFixed(2)); // "1234.57" — NOTE: a string comes back
console.log(Number("42px"));        // NaN — Number refuses partial reads

Convert with Number()/String() — explicit and strict. Beware toFixed: it formats (returns a string), it does not round the number in place.

Intl: formatting for humans

console.log(new Intl.NumberFormat("de-DE").format(1234.5)); // 1.234,5
console.log(new Date().toLocaleDateString("en-GB"));        // locale date

Never hand-format currencies and dates — the built-in Intl knows every locale's rules.

A taste of regex

console.log(/2026/.test(file));      // true — "does the pattern appear?"
console.log(file.match(/\d{4}/)[0]); // "2026" — the first four digits

Regular expressions match patterns. Two methods cover day one: .test() (boolean) and .match() (what was found). Reach for plain string methods first; regex is for patterns, not for homework.

Practice: the string lab

The task

Run foundations/11_strings_lab.js with node, predicting each line. Then build one line of "form output" yourself: trim a fake input, produce Hello, Ada! with a template literal, and extract a filename's extension with slice(-4).

The checklist

  • You can explain why a method call alone never changed name.
  • You reach for template literals instead of + for sentences.
  • You know what "👍".length returns and the safe way to count characters.
  • You know toFixed returns a string, and Number() refuses partial reads.