JavaScript Basics #6 Strings and Template Literals

6 min read

In #5 Objects and Arrays we saw two structures for grouping data. This post takes a deep dive into one of them — strings: common methods, template literals, and regex basics.

Building strings — three quote types #

There are three quote types for strings in JavaScript.

three string types
const a = 'single quote';
const b = "double quote";
const c = `backtick (template literal)`;

' (single) and " (double) have no semantic difference. Pick one and stick to it as a team convention. This series uses single quotes.

The third — backtick — is the powerful template literal. We dig into it shortly.

Common methods #

Length and index access #

basic info
const s = 'JavaScript';

s.length;      // 10
s[0];          // 'J'
s.at(0);       // 'J'
s.at(-1);      // 't' (negative index — only at)

at() is a method added in ES2022. It lets you access from the end with a negative index. Shorter and clearer than s[s.length - 1].

Searching #

search / contains
const s = 'hello world';

s.includes('world');     // true
s.indexOf('world');       // 6
s.indexOf('foo');         // -1 (-1 if not found)
s.startsWith('hello');    // true
s.endsWith('world');      // true

For searching, includes / startsWith / endsWith are almost always the most intuitive choice. Use indexOf only when you also need the position.

Slicing / extracting #

substrings
const s = 'hello world';

s.slice(0, 5);       // 'hello'
s.slice(6);          // 'world'
s.slice(-5);         // 'world' (5 chars from the end)
s.substring(0, 5);   // 'hello' (nearly the same as slice)

In the past, substring/substr/slice differed in subtle ways — in new code, standardize on slice. It accepts negative indices and is the most intuitive of the three.

Conversion / cleanup #

conversion
const s = '  Hello World  ';

s.trim();              // 'Hello World'
s.trimStart();         // 'Hello World  '
s.trimEnd();           // '  Hello World'
s.toLowerCase();       // '  hello world  '
s.toUpperCase();       // '  HELLO WORLD  '
s.replaceAll(' ', '_'); // '__Hello_World__'

replaceAll was added in ES2021. Previously you had to use replace with a /g regex — for simple replacements, replaceAll is cleaner.

Split / join #

split / join
const s = 'apple,banana,grape';

s.split(',');                 // ['apple', 'banana', 'grape']
['apple', 'banana'].join(',');  // 'apple,banana'

// per character
'hello'.split('');            // ['h', 'e', 'l', 'l', 'o']

// join with empty string
['h', 'i'].join('');          // 'hi'

split('') for per-character splitting can break on non-ASCII (emoji, etc.). For Unicode-safe splitting, use [...s] (spread) or Array.from(s).

Unicode-safe splitting
const s = 'a😀b';
s.split('');          // ['a', '\uD83D', '\uDE00', 'b']  ← broken
[...s];               // ['a', '😀', 'b']
Array.from(s);        // ['a', '😀', 'b']

Template literals — backticks shine #

Almost any place you’d concatenate strings with +, backticks are nicer.

string composition
const name = 'Curtis';
const age = 30;

// + operator
const a = 'hi, ' + name + ' (' + age + ')';

// template literal
const b = `hi, ${name} (${age})`;

Inside ${...} you can put any expression.

const items = ['apple', 'banana', 'grape'];

`total ${items.length}`;
`first: ${items[0]}`;
`sum: ${1 + 2 + 3}`;
`status: ${age >= 18 ? 'adult' : 'minor'}`;

Multiline strings #

multiline
const html = `
  <div>
    <h1>title</h1>
    <p>body</p>
  </div>
`;

In the old days you wrote '<div>\n<h1>...' with literal \n. Backticks include newlines as-is.

Tagged Template — function call #

A slightly advanced usage. Putting a function before backticks passes the template into that function.

tagged template
function highlight(strings, ...values) {
  return strings.reduce((acc, s, i) => {
    return acc + s + (values[i] !== undefined ? `[${values[i]}]` : '');
  }, '');
}

const name = 'Curtis';
const age = 30;
highlight`name is ${name}, age is ${age}`;
// 'name is [Curtis], age is [30]'

A pattern often used by libraries to defend against SQL/HTML injection. Don’t worry if it looks unfamiliar at first — take a closer look when you encounter it in the wild.

Number/string conversion #

between number and string
String(42);              // '42'
(42).toString();         // '42'
`${42}`;                 // '42' — most common idiom

Number('42');             // 42
parseInt('42px');         // 42 — leading part only
parseFloat('3.14');       // 3.14
+'42';                    // 42 — unary plus

Number('abc');            // NaN
parseInt('abc');          // NaN

Number(...) returns NaN if the entire string is not a valid number. parseInt/parseFloat parse as much as they can from the start. If your input has a unit like 42px, those are the better fit.

Regular expressions — pattern matching #

A literal of the shape /pattern/flags.

regex basics
const re = /hello/i;       // case-insensitive
'Hello World'.match(re);   // ['Hello', ...]
re.test('Hi');             // false
re.test('Hello');          // true

Common metacharacters #

PatternMeaning
.any single character
\ddigit
\wword character (alphanumeric/_)
\swhitespace
^ / $line start / end
+one or more
*zero or more
?zero or one
[abc]one of a, b, c
(...)capture group

Common cases #

check / extract / replace
// rough email check
/^[^@]+@[^@]+\.[^@]+$/.test('me@example.com');   // true

// extract digits only
'price: 1500 KRW'.match(/\d+/);   // ['1500', ...]

// all matches
'a1 b2 c3'.matchAll(/[a-z]\d/g);  // iterable

// replace
'2026-05-04'.replace(/-/g, '/');  // '2026/05/04'

The g flag — means find all matches (global). Without it, only the first.

Capture groups #

splitting via capture groups
const date = '2026-05-04';
const m = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
// m: ['2026-05-04', '2026', '05', '04', ...]

const [, year, month, day] = m;
console.log(year, month, day);   // 2026 05 04

The parts inside parentheses (...) are captured and added to the result array. Named groups too.

named capture
const m = '2026-05-04'.match(
  /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/
);
m.groups.year;    // '2026'
m.groups.month;   // '05'
m.groups.day;     // '04'

(?<name>...) form. Pull out by name from groups.

When you need regex / when you don’t #

Regex is powerful but gets hard to read quickly. In these cases, plain string methods are almost always better:

regex not needed here
// simple search
s.includes('foo');               // O
s.match(/foo/);                  // X (overkill)

// start/end check
s.startsWith('http');            // O
s.match(/^http/);                // X

// simple replace
s.replaceAll('foo', 'bar');      // O
s.replace(/foo/g, 'bar');        // X (overkill)

Where regex shines — when the pattern varies or capture is needed: date/email format checks, log parsing, etc.

Wrap-up #

What we covered:

  • Three quote types — '/" mean the same; ` is the template literal
  • Common methods — length/at/includes/slice/split/join/replaceAll
  • Unicode-safe splitting via [...s] or Array.from(s)
  • Template literals — expressions in ${}, multiline strings
  • Conversion — String()/Number()/parseInt(), +value idiom
  • Regex basics — metacharacters, g flag, capture groups
  • For simple search/replace, methods are clearer than regex

In the next post (#7 Modules) — the final basics post — we cover splitting code across files: ES Modules and import/export patterns.

X