JavaScript Strings
JavaScript strings interview guide — immutability, search, slice, transform, split/join, templates, regex, Unicode, and practice problems with solutions.
Introduction
Strings show up everywhere — URLs, form validation, slug generation, and live-coding rounds. This guide covers the methods you need to know, common interview traps, and practice problems with solutions.
Course Reference
Quick index
1. Creation & immutability
Create strings
const single = 'hello'
const double = 'world'
const template = `hello ${double}` // 'hello world'
const multi = `Line 1
Line 2`Strings are immutable
let s = 'hello'
s[0] = 'H' // does not mutate (ignored in strict mode)
s = s.toUpperCase() // must reassign — returns new string 'HELLO'2. Access & length
const s = 'hello'
s.length // 5
s[0] // 'h'
s.charAt(0) // 'h'
s.charAt(99) // '' — out of bounds, no error
s.at(-1) // 'o' — ES2022 negative index
s.at(-2) // 'l'Character codes
'A'.charCodeAt(0) // 65
String.fromCharCode(72, 105) // 'Hi'
'😀'.codePointAt(0) // 128512
String.fromCodePoint(0x1f600) // '😀'Unicode length trap
'😀'.length // 2 — UTF-16 code units
;[...'😀'].length // 1 — spread by code point
Array.from('😀').length // 13. Search methods
| Method | Returns | Notes |
|---|---|---|
includes(sub) | boolean | Case-sensitive |
startsWith(sub) | boolean | Optional start position |
endsWith(sub) | boolean | Optional end position |
indexOf(sub) | number | -1 if not found |
lastIndexOf(sub) | number | Search from end |
search(regex) | number | Regex only |
const email = 'user@company.io'
email.includes('@') // true
email.startsWith('user') // true
email.endsWith('.io') // true
email.indexOf('@') // 4
email.lastIndexOf('.') // 12
// Case-insensitive check
email.toLowerCase().includes('USER'.toLowerCase())4. Extract: slice, substring
const s = 'hello world'
s.slice(0, 5) // 'hello' — [start, end)
s.slice(6) // 'world'
s.slice(-5) // 'world' — negative start
s.substring(0, 5) // 'hello' — swaps if start > end
s.substr(6, 5) // 'world' — deprecated, avoid5. Transform & replace
'Hello'.toLowerCase() // 'hello'
'hello'.toUpperCase() // 'HELLO'
'hello'.replace('l', 'x') // 'hexlo' — first only
'hello'.replaceAll('l', 'x') // 'hexxo'
'hello'.replace(/l/g, 'x') // 'hexxo'
// replace with callback
'user-name-id'.replace(/-(\w)/g, (_, ch) => ch.toUpperCase())
// 'userNameId'repeat
'•'.repeat(3) // '•••'
'0'.repeat(4) // '0000'6. Trim & pad
' hello '.trim() // 'hello'
' hello '.trimStart() // 'hello '
' hello '.trimEnd() // ' hello'
'42'.padStart(5, '0') // '00042'
'42'.padEnd(5, '-') // '42---'Practical use:
String(orderId).padStart(6, '0') // '000042'7. Split & join
'a,b,c'.split(',') // ['a', 'b', 'c']
'a,b,c'.split(',', 2) // ['a', 'b'] — limit
'hello'.split('') // ['h','e','l','l','o']
;['a', 'b', 'c'].join('-') // 'a-b-c'Reverse words
function reverseWords(s) {
return s.trim().split(/\s+/).reverse().join(' ')
}Efficient string building
// Bad — O(n²) in many engines
let result = ''
for (const chunk of chunks) result += chunk
// Good — O(n)
const result = chunks.join('')8. Template literals
const name = 'Alice'
const salary = 90000
const msg = `Hello, ${name}! Salary: $${salary}`
const html = `
<article>
<h2>${name}</h2>
</article>
`Tagged templates
function highlight(strings, ...values) {
return strings.reduce((acc, str, i) => {
const val = values[i] ?? ''
return acc + str + (val ? `<mark>${val}</mark>` : '')
}, '')
}
const query = 'react'
highlight`Search results for ${query}`String.raw
String.raw`C:\new\folder` // 'C:\\new\\folder'9. Regex essentials
const slug = ' Hello World! '
.trim()
.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-')
// 'hello-world'
;/^[\w.-]+@[\w.-]+\.\w+$/.test('user@co.io') // basic email check
'price: $10, tax: $2'.match(/\$(\d+)/g) // ['$10', '$2']
;[...'a1 b2'.matchAll(/\d+/g)].map((m) => m[0]) // ['1', '2']10. Unicode & static methods
normalize
const composed = 'e\u0301' // e + combining accent
composed.normalize('NFC') // single 'é'localeCompare
const names = ['Zoe', 'alice', 'Bob']
names.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))Intl formatting
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(1499.99)
new Intl.DateTimeFormat('en-US', { dateStyle: 'medium' }).format(new Date())11. Utility patterns
Highlight search term
function highlightMatch(text, term) {
if (!term) return text
const i = text.toLowerCase().indexOf(term.toLowerCase())
if (i === -1) return text
return text.slice(0, i) + '<mark>' + text.slice(i, i + term.length) + '</mark>' + text.slice(i + term.length)
}Truncate with ellipsis
function truncate(str, max = 50) {
if (str.length <= max) return str
return str.slice(0, max - 1).trimEnd() + '…'
}Parse query string
function parseQuery(search = '') {
const params = new URLSearchParams(search.startsWith('?') ? search : `?${search}`)
return Object.fromEntries(params.entries())
}
parseQuery('?page=2&sort=name') // { page: '2', sort: 'name' }Title case & slug
function toTitleCase(str) {
return str
.trim()
.split(/\s+/)
.map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase())
.join(' ')
}
function toSlug(str) {
return str
.trim()
.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-')
}Quick reference
| Task | API |
|---|---|
| Contains | includes, startsWith, endsWith |
| Find position | indexOf, lastIndexOf, search |
| Substring | slice |
| Replace | replace, replaceAll |
| Case | toLowerCase, toUpperCase |
| Whitespace | trim, trimStart, trimEnd |
| Array ↔ string | split, join |
| Interpolation | template literals `${}` |
| Unicode-safe length | [...str].length |
| Repeat | repeat(n) |
| Pad | padStart, padEnd |
| Locale sort | localeCompare |
| Parse query | URLSearchParams |
Practice Problems
Quick index
1. Fundamentals (T-001 – T-020)
2. Article dataset (T-021 – T-040)
3. Regex, templates & advanced (T-041 – T-048)
1. Fundamentals (T-001 – T-020)
T-001: Create strings with quotes and template literal
Answer:
const a = 'hello'
const b = 'world'
const c = `hello ${b}` // 'hello world'T-002: Length and first/last character
Answer:
const s = 'javascript'
s.length // 10
s[0] // 'j'
s[s.length - 1] // 't'
s.at(-1) // 't'T-003: charAt() vs bracket notation
Answer:
const s = 'hi'
s.charAt(0) // 'h'
s[0] // 'h'
s.charAt(5) // ''
s[5] // undefinedT-004: at() with negative index
Answer:
const s = 'hello'
s.at(-1) // 'o'
s.at(-2) // 'l'T-005: String immutability
Answer:
let s = 'hello'
s[0] = 'H' // fails silently / strict: no effect
s = 'H' + s.slice(1) // 'Hello' — new stringT-006: Uppercase and lowercase
Answer:
'Hello'.toUpperCase() // 'HELLO'
'Hello'.toLowerCase() // 'hello'T-007: Trim whitespace
Answer:
const s = ' hello '
s.trim() // 'hello'
s.trimStart() // 'hello '
s.trimEnd() // ' hello'T-008: includes, startsWith, endsWith
Answer:
const s = 'hello world'
s.includes('world') // true
s.startsWith('hello') // true
s.endsWith('ld') // trueT-009: indexOf and lastIndexOf
Answer:
const s = 'hello world hello'
s.indexOf('hello') // 0
s.lastIndexOf('hello') // 12
s.indexOf('xyz') // -1T-010: Extract with slice
Answer:
const s = 'hello world'
s.slice(0, 5) // 'hello'
s.slice(6) // 'world'
s.slice(-5) // 'world'T-011: slice vs substring
Answer:
'hello'.slice(-3) // 'llo'
'hello'.substring(-3) // 'hello' — negative → 0T-012: replace first occurrence
Answer:
'hello'.replace('l', 'x') // 'hexlo'T-013: replaceAll
Answer:
'hello'.replaceAll('l', 'x') // 'hexxo'
'hello'.replace(/l/g, 'x') // same with regexT-014: split into array
Answer:
'a,b,c'.split(',') // ['a','b','c']
'hello'.split('') // ['h','e','l','l','o']T-015: join array to string
Answer:
;['hello', 'world'].join(' ') // 'hello world'
;['a', 'b', 'c'].join('-') // 'a-b-c'T-016: padStart and padEnd
Answer:
'42'.padStart(5, '0') // '00042'
'42'.padEnd(5, '-') // '42---'T-017: repeat
Answer:
'-'.repeat(10) // '----------'
'ha'.repeat(3) // 'hahaha'T-018: Character codes
Answer:
'A'.charCodeAt(0) // 65
String.fromCharCode(72, 105) // 'Hi'T-019: Emoji length trap
Answer:
'😀'.length // 2
;[...'😀'].length // 1T-020: Template literal HTML snippet
Answer:
const name = 'Alice'
const role = 'admin'
const html = `<div class="user"><h2>${name}</h2><span>${role}</span></div>`2. Article dataset (T-021 – T-040)
Shared setup:
const articles = [
{ id: 1, title: ' Learn JavaScript ', author: 'alice@company.io', tags: 'js,web,api' },
{ id: 2, title: 'React Hooks Guide', author: 'bob@mail.com', tags: 'react,hooks' },
{ id: 3, title: 'NODE.JS PERFORMANCE', author: 'carol@company.io', tags: 'node,perf' },
{ id: 4, title: 'css tricks for beginners', author: 'dave@mail.com', tags: 'css,ui' },
{ id: 5, title: 'API Design Patterns ', author: 'eve@startup.io', tags: 'api,design,js' },
]T-021: Trimmed lowercased titles
Answer:
const cleaned = articles.map((a) => a.title.trim().toLowerCase())T-022: Filter by @company.io email
Answer:
const company = articles.filter((a) => a.author.includes('@company.io'))T-023: Extract email domain
Answer:
const domains = articles.map((a) => a.author.split('@')[1])T-024: Create URL slug from title
Answer:
function toSlug(title) {
return title
.trim()
.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-')
}T-025: Case-insensitive title search
Answer:
const term = 'javascript'
const found = articles.filter((a) => a.title.toLowerCase().includes(term))T-026: Split tags into array
Answer:
const withTagArrays = articles.map((a) => ({
...a,
tagList: a.tags.split(','),
}))T-027: Join tags with |
Answer:
articles.map((a) => a.tags.split(',').join(' | '))T-028: Format id as 4-digit string
Answer:
articles.map((a) => String(a.id).padStart(4, '0'))
// ['0001', '0002', ...]T-029: Spaces to underscores
Answer:
articles.map((a) => a.title.trim().replaceAll(' ', '_'))T-030: Count words in title
Answer:
function wordCount(title) {
return title.trim().split(/\s+/).length
}T-031: Reverse word order
Answer:
function reverseWords(s) {
return s.trim().split(/\s+/).reverse().join(' ')
}T-032: All emails end with .com or .io
Answer:
const allValid = articles.every((a) => a.author.endsWith('.com') || a.author.endsWith('.io'))T-033: Username before @
Answer:
const usernames = articles.map((a) => a.author.split('@')[0])T-034: Title case
Answer:
function toTitleCase(str) {
return str
.trim()
.split(/\s+/)
.map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase())
.join(' ')
}T-035: Truncate with ellipsis
Answer:
function truncate(str, max = 20) {
const t = str.trim()
if (t.length <= max) return t
return t.slice(0, max - 1) + '…'
}T-036: Search title or tags
Answer:
function searchArticles(list, term) {
const q = term.toLowerCase()
return list.filter((a) => a.title.toLowerCase().includes(q) || a.tags.toLowerCase().includes(q))
}T-037: Extract TLD from email
Answer:
const tlds = articles.map((a) => a.author.slice(a.author.lastIndexOf('.')))
// '.io', '.com', ...T-038: Parse log line key-value pairs
Answer:
function parseLog(line) {
const parts = line.replace(/^\[.*?\]\s*/, '').split(' ')
return Object.fromEntries(parts.map((p) => p.split('=')).filter(([k]) => k))
}
parseLog('[ERROR] user=alice code=500')
// { user: 'alice', code: '500' }T-039: Highlight search term in title
Answer:
function highlight(text, term) {
const i = text.toLowerCase().indexOf(term.toLowerCase())
if (i === -1) return text
return text.slice(0, i) + '<mark>' + text.slice(i, i + term.length) + '</mark>' + text.slice(i + term.length)
}T-040: Sort titles with localeCompare
Answer:
const sorted = [...articles].sort((a, b) => a.title.trim().localeCompare(b.title.trim(), 'en', { sensitivity: 'base' }))3. Regex, templates & advanced (T-041 – T-048)
T-041: Validate email with regex
Answer:
const emailRegex = /^[\w.-]+@[\w.-]+\.\w+$/
emailRegex.test('alice@company.io') // true
emailRegex.test('not-an-email') // falseT-042: Extract numbers with match
Answer:
'order 42 costs 19.99'.match(/\d+(\.\d+)?/g)
// ['42', '19.99']T-043: matchAll for digit groups
Answer:
const matches = [...'a1 b22 c333'.matchAll(/\d+/g)].map((m) => m[0])
// ['1', '22', '333']T-044: Multi-line template literal
Answer:
const name = 'Alice'
const date = new Date().toDateString()
const card = `User: ${name}
Date: ${date}`T-045: Tagged template with <strong>
Answer:
function strong(strings, ...values) {
return strings.reduce((acc, str, i) => {
const val = values[i] ?? ''
return acc + str + (val ? `<strong>${val}</strong>` : '')
}, '')
}
const name = 'Alice'
strong`Hello, ${name}!` // 'Hello, <strong>Alice</strong>!'T-046: String.raw for file paths
Answer:
const winPath = String.raw`C:\Users\Alice\Documents`
// 'C:\\Users\\Alice\\Documents'T-047: Unicode normalize
Answer:
const composed = 'e\u0301'
composed.normalize('NFC') // 'é' (single code point)T-048: Parse query string
Answer:
function parseQuery(search = '') {
const params = new URLSearchParams(search.startsWith('?') ? search : '?' + search)
return Object.fromEntries(params.entries())
}
parseQuery('?page=2&sort=name')
// { page: '2', sort: 'name' }Quick reference — method by task
| Tasks | Primary APIs |
|---|---|
| T-001 – T-005 | literals, .length, charAt, .at(), immutability |
| T-006 – T-013 | toUpperCase, trim, includes, indexOf, slice, replace, replaceAll |
| T-014 – T-020 | split, join, padStart, repeat, charCodeAt, templates |
| T-021 – T-040 | trim, slug, title case, truncate, highlight, localeCompare |
| T-041 – T-048 | regex, matchAll, tagged templates, String.raw, URLSearchParams |
Interview tip: Practice explaining T-005 (immutability), T-011 (slice vs substring), and T-019 (emoji length) aloud.
Subscribe to my newsletter
Stay up to date and get notified when I share new contents.
No spam ever, unsubscribe anytime