Kazi Rahamatullah
Kazi Rahamatullah
AboutProjectsBlogContact
UsesBooks
ResumeView CV
Kazi Rahamatullah

© Copyright 2026 Kazi Rahamatullah

AboutProjectsBlogBooksUses
Twitter/XGitHubProduct HuntCodeSandbox
Back to Blog
JavaScriptStringsInterview PreparationFrontend DevelopmentRegex

JavaScript Strings

JavaScript strings interview guide — immutability, search, slice, transform, split/join, templates, regex, Unicode, and practice problems with solutions.

Jul 4, 202619 min read

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

#Section
1Creation & immutability
2Access & length
3Search methods
4Extract: slice, substring
5Transform & replace
6Trim & pad
7Split & join
8Template literals
9Regex essentials
10Unicode & static methods
11Utility patterns

1. Creation & immutability

Create strings

javascript
const single = 'hello'
const double = 'world'
const template = `hello ${double}` // 'hello world'
 
const multi = `Line 1
Line 2`

Strings are immutable

javascript
let s = 'hello'
s[0] = 'H' // does not mutate (ignored in strict mode)
s = s.toUpperCase() // must reassign — returns new string 'HELLO'

Interview Answer

Strings are primitives and immutable. Every method that "changes" a string returns a new string. For large text building in loops, use an array + join instead of +=.

Back to index


2. Access & length

javascript
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

javascript
'A'.charCodeAt(0) // 65
String.fromCharCode(72, 105) // 'Hi'
'😀'.codePointAt(0) // 128512
String.fromCodePoint(0x1f600) // '😀'

Unicode length trap

javascript
'😀'.length // 2 — UTF-16 code units
;[...'😀'].length // 1 — spread by code point
Array.from('😀').length // 1

Interview Answer

.length counts UTF-16 code units, not visual characters. Use spread or Array.from for emoji-safe length.

Back to index


3. Search methods

MethodReturnsNotes
includes(sub)booleanCase-sensitive
startsWith(sub)booleanOptional start position
endsWith(sub)booleanOptional end position
indexOf(sub)number-1 if not found
lastIndexOf(sub)numberSearch from end
search(regex)numberRegex only
javascript
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())

Back to index


4. Extract: slice, substring

javascript
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, avoid

Interview Answer

Prefer slice — supports negative indices and behaves like array slice. substring treats negative args as 0.

Back to index


5. Transform & replace

javascript
'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

javascript
'•'.repeat(3) // '•••'
'0'.repeat(4) // '0000'

Back to index


6. Trim & pad

javascript
'  hello  '.trim() // 'hello'
'  hello  '.trimStart() // 'hello  '
'  hello  '.trimEnd() // '  hello'
 
'42'.padStart(5, '0') // '00042'
'42'.padEnd(5, '-') // '42---'

Practical use:

javascript
String(orderId).padStart(6, '0') // '000042'

Back to index


7. Split & join

javascript
'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

javascript
function reverseWords(s) {
  return s.trim().split(/\s+/).reverse().join(' ')
}

Efficient string building

javascript
// Bad — O(n²) in many engines
let result = ''
for (const chunk of chunks) result += chunk
 
// Good — O(n)
const result = chunks.join('')

Back to index


8. Template literals

javascript
const name = 'Alice'
const salary = 90000
 
const msg = `Hello, ${name}! Salary: $${salary}`
 
const html = `
  <article>
    <h2>${name}</h2>
  </article>
`

Tagged templates

javascript
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

javascript
String.raw`C:\new\folder` // 'C:\\new\\folder'

Back to index


9. Regex essentials

javascript
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']

Interview Answer

Use match with g for all matches (no capture groups with g). Use matchAll when you need capture groups for each match.

Back to index


10. Unicode & static methods

normalize

javascript
const composed = 'e\u0301' // e + combining accent
composed.normalize('NFC') // single 'é'

localeCompare

javascript
const names = ['Zoe', 'alice', 'Bob']
names.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))

Intl formatting

javascript
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(1499.99)
new Intl.DateTimeFormat('en-US', { dateStyle: 'medium' }).format(new Date())

Back to index


11. Utility patterns

Highlight search term

javascript
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

javascript
function truncate(str, max = 50) {
  if (str.length <= max) return str
  return str.slice(0, max - 1).trimEnd() + '…'
}

Parse query string

javascript
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

javascript
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, '-')
}

Back to index


Quick reference

TaskAPI
Containsincludes, startsWith, endsWith
Find positionindexOf, lastIndexOf, search
Substringslice
Replacereplace, replaceAll
CasetoLowerCase, toUpperCase
Whitespacetrim, trimStart, trimEnd
Array ↔ stringsplit, join
Interpolationtemplate literals `${}`
Unicode-safe length[...str].length
Repeatrepeat(n)
PadpadStart, padEnd
Locale sortlocaleCompare
Parse queryURLSearchParams

Practice Problems

Quick index

1. Fundamentals (T-001 – T-020)

#Question
T-001: Create strings with quotes and template literal
T-002: Length and first/last character
T-003: charAt() vs bracket notation
T-004: at() with negative index
T-005: String immutability
T-006: Uppercase and lowercase
T-007: Trim whitespace
T-008: includes, startsWith, endsWith
T-009: indexOf and lastIndexOf
T-010: Extract with slice
T-011: slice vs substring
T-012: replace first occurrence
T-013: replaceAll
T-014: split into array
T-015: join array to string
T-016: padStart and padEnd
T-017: repeat
T-018: Character codes
T-019: Emoji length trap
T-020: Template literal HTML snippet

2. Article dataset (T-021 – T-040)

#Question
T-021: Trimmed lowercased titles
T-022: Filter by @company.io email
T-023: Extract email domain
T-024: Create URL slug from title
T-025: Case-insensitive title search
T-026: Split tags into array
T-027: Join tags with pipe separator
T-028: Format id as 4-digit string
T-029: Spaces to underscores
T-030: Count words in title
T-031: Reverse word order
T-032: All emails end with .com or .io
T-033: Username before @
T-034: Title case
T-035: Truncate with ellipsis
T-036: Search title or tags
T-037: Extract TLD from email
T-038: Parse log line key-value pairs
T-039: Highlight search term in title
T-040: Sort titles with localeCompare

3. Regex, templates & advanced (T-041 – T-048)

#Question
T-041: Validate email with regex
T-042: Extract numbers with match
T-043: matchAll for digit groups
T-044: Multi-line template literal
T-045: Tagged template with <strong>
T-046: String.raw for file paths
T-047: Unicode normalize
T-048: Parse query string

1. Fundamentals (T-001 – T-020)

T-001: Create strings with quotes and template literal

Answer:

Note

Three ways to create strings. Template literals allow interpolation and multiline text.

javascript
const a = 'hello'
const b = 'world'
const c = `hello ${b}` // 'hello world'

Back to index


T-002: Length and first/last character

Answer:

Note

Use .length and index 0 / length - 1, or .at(-1) for the last char.

javascript
const s = 'javascript'
s.length // 10
s[0] // 'j'
s[s.length - 1] // 't'
s.at(-1) // 't'

Back to index


T-003: charAt() vs bracket notation

Answer:

Note

Both return a character. charAt returns empty string out of bounds; bracket returns undefined.

javascript
const s = 'hi'
s.charAt(0) // 'h'
s[0] // 'h'
s.charAt(5) // ''
s[5] // undefined

Back to index


T-004: at() with negative index

Answer:

Note

ES2022 .at(-1) reads from the end — same idea as array .at().

javascript
const s = 'hello'
s.at(-1) // 'o'
s.at(-2) // 'l'

Back to index


T-005: String immutability

Answer:

Warning

Strings cannot be mutated in place. Assignment creates a new reference to a new string.

javascript
let s = 'hello'
s[0] = 'H' // fails silently / strict: no effect
s = 'H' + s.slice(1) // 'Hello' — new string

Back to index


T-006: Uppercase and lowercase

Answer:

Note

toUpperCase and toLowerCase return new strings.

javascript
'Hello'.toUpperCase() // 'HELLO'
'Hello'.toLowerCase() // 'hello'

Back to index


T-007: Trim whitespace

Answer:

Note

Remove whitespace from both ends or one side only.

javascript
const s = '  hello  '
s.trim() // 'hello'
s.trimStart() // 'hello  '
s.trimEnd() // '  hello'

Back to index


T-008: includes, startsWith, endsWith

Answer:

Note

Boolean search methods — all case-sensitive by default.

javascript
const s = 'hello world'
s.includes('world') // true
s.startsWith('hello') // true
s.endsWith('ld') // true

Back to index


T-009: indexOf and lastIndexOf

Answer:

Note

Return index or -1 if not found.

javascript
const s = 'hello world hello'
s.indexOf('hello') // 0
s.lastIndexOf('hello') // 12
s.indexOf('xyz') // -1

Back to index


T-010: Extract with slice

Answer:

Note

slice(start, end) — end is exclusive. Negative start counts from end.

javascript
const s = 'hello world'
s.slice(0, 5) // 'hello'
s.slice(6) // 'world'
s.slice(-5) // 'world'

Back to index


T-011: slice vs substring

Answer:

Note

slice supports negative indices. substring swaps arguments if start > end and treats negatives as 0.

javascript
'hello'.slice(-3) // 'llo'
'hello'.substring(-3) // 'hello' — negative → 0

Back to index


T-012: replace first occurrence

Answer:

Note

Replaces only the first match unless using regex with g.

javascript
'hello'.replace('l', 'x') // 'hexlo'

Back to index


T-013: replaceAll

Answer:

Note

Replaces every occurrence of a substring.

javascript
'hello'.replaceAll('l', 'x') // 'hexxo'
'hello'.replace(/l/g, 'x') // same with regex

Back to index


T-014: split into array

Answer:

Note

Split on delimiter or empty string for characters.

javascript
'a,b,c'.split(',') // ['a','b','c']
'hello'.split('') // ['h','e','l','l','o']

Back to index


T-015: join array to string

Answer:

Note

Inverse of split — concatenates with separator.

javascript
;['hello', 'world'].join(' ') // 'hello world'
;['a', 'b', 'c'].join('-') // 'a-b-c'

Back to index


T-016: padStart and padEnd

Answer:

Note

Pad to target length with fill string.

javascript
'42'.padStart(5, '0') // '00042'
'42'.padEnd(5, '-') // '42---'

Back to index


T-017: repeat

Answer:

Note

Repeat string n times.

javascript
'-'.repeat(10) // '----------'
'ha'.repeat(3) // 'hahaha'

Back to index


T-018: Character codes

Answer:

Note

charCodeAt gets code unit; fromCharCode builds string from codes.

javascript
'A'.charCodeAt(0) // 65
String.fromCharCode(72, 105) // 'Hi'

Back to index


T-019: Emoji length trap

Answer:

Note

Emoji use surrogate pairs — .length is 2. Spread counts code points.

javascript
'😀'.length // 2
;[...'😀'].length // 1

Back to index


T-020: Template literal HTML snippet

Answer:

Note

Embed expressions inside backticks for dynamic strings.

javascript
const name = 'Alice'
const role = 'admin'
 
const html = `<div class="user"><h2>${name}</h2><span>${role}</span></div>`

Back to index


2. Article dataset (T-021 – T-040)

Shared setup:

javascript
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:

Note

Map to new strings — trim then toLowerCase without mutating source.

javascript
const cleaned = articles.map((a) => a.title.trim().toLowerCase())

Back to index


T-022: Filter by @company.io email

Answer:

Note

includes on author field.

javascript
const company = articles.filter((a) => a.author.includes('@company.io'))

Back to index


T-023: Extract email domain

Answer:

Note

Split on @ and take index 1.

javascript
const domains = articles.map((a) => a.author.split('@')[1])

Back to index


T-024: Create URL slug from title

Answer:

Note

Trim, lowercase, replace spaces with hyphens, remove special chars.

javascript
function toSlug(title) {
  return title
    .trim()
    .toLowerCase()
    .replace(/[^\w\s-]/g, '')
    .replace(/\s+/g, '-')
}

Back to index


T-025: Case-insensitive title search

Answer:

Note

Compare lowercased strings.

javascript
const term = 'javascript'
const found = articles.filter((a) => a.title.toLowerCase().includes(term))

Back to index


T-026: Split tags into array

Answer:

Note

split(',') per article.

javascript
const withTagArrays = articles.map((a) => ({
  ...a,
  tagList: a.tags.split(','),
}))

Back to index


T-027: Join tags with |

Answer:

Note

split then join for display format.

javascript
articles.map((a) => a.tags.split(',').join(' | '))

Back to index


T-028: Format id as 4-digit string

Answer:

Note

String(id).padStart(4, '0').

javascript
articles.map((a) => String(a.id).padStart(4, '0'))
// ['0001', '0002', ...]

Back to index


T-029: Spaces to underscores

Answer:

Note

replaceAll(' ', '_') after trim.

javascript
articles.map((a) => a.title.trim().replaceAll(' ', '_'))

Back to index


T-030: Count words in title

Answer:

Note

Split on whitespace and count length.

javascript
function wordCount(title) {
  return title.trim().split(/\s+/).length
}

Back to index


T-031: Reverse word order

Answer:

Note

trim → split → reverse → join.

javascript
function reverseWords(s) {
  return s.trim().split(/\s+/).reverse().join(' ')
}

Back to index


T-032: All emails end with .com or .io

Answer:

Note

every with endsWith check.

javascript
const allValid = articles.every((a) => a.author.endsWith('.com') || a.author.endsWith('.io'))

Back to index


T-033: Username before @

Answer:

Note

split('@')[0].

javascript
const usernames = articles.map((a) => a.author.split('@')[0])

Back to index


T-034: Title case

Answer:

Note

Capitalize first letter of each word.

javascript
function toTitleCase(str) {
  return str
    .trim()
    .split(/\s+/)
    .map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase())
    .join(' ')
}

Back to index


T-035: Truncate with ellipsis

Answer:

Note

Slice to max length and append ….

javascript
function truncate(str, max = 20) {
  const t = str.trim()
  if (t.length <= max) return t
  return t.slice(0, max - 1) + '…'
}

Back to index


T-036: Search title or tags

Answer:

Note

Case-insensitive match in either field.

javascript
function searchArticles(list, term) {
  const q = term.toLowerCase()
  return list.filter((a) => a.title.toLowerCase().includes(q) || a.tags.toLowerCase().includes(q))
}

Back to index


T-037: Extract TLD from email

Answer:

Note

Last segment after final dot.

javascript
const tlds = articles.map((a) => a.author.slice(a.author.lastIndexOf('.')))
// '.io', '.com', ...

Back to index


T-038: Parse log line key-value pairs

Answer:

Note

Split tokens, parse key=value pairs into object.

javascript
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' }

Back to index


T-039: Highlight search term in title

Answer:

Note

Find index case-insensitively, wrap match in <mark>.

javascript
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)
}

Back to index


T-040: Sort titles with localeCompare

Answer:

Note

Locale-aware alphabetical sort.

javascript
const sorted = [...articles].sort((a, b) => a.title.trim().localeCompare(b.title.trim(), 'en', { sensitivity: 'base' }))

Back to index


3. Regex, templates & advanced (T-041 – T-048)

T-041: Validate email with regex

Answer:

Note

Basic pattern check — not production-grade but common in interviews.

javascript
const emailRegex = /^[\w.-]+@[\w.-]+\.\w+$/
emailRegex.test('alice@company.io') // true
emailRegex.test('not-an-email') // false

Back to index


T-042: Extract numbers with match

Answer:

Note

Global regex returns all matches.

javascript
'order 42 costs 19.99'.match(/\d+(\.\d+)?/g)
// ['42', '19.99']

Back to index


T-043: matchAll for digit groups

Answer:

Note

Iterator of match objects — spread to array.

javascript
const matches = [...'a1 b22 c333'.matchAll(/\d+/g)].map((m) => m[0])
// ['1', '22', '333']

Back to index


T-044: Multi-line template literal

Answer:

Note

Backticks allow newlines and interpolated expressions.

javascript
const name = 'Alice'
const date = new Date().toDateString()
 
const card = `User: ${name}
Date: ${date}`

Back to index


T-045: Tagged template with <strong>

Answer:

Note

Tag function receives string parts and interpolated values.

javascript
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>!'

Back to index


T-046: String.raw for file paths

Answer:

Note

Preserves backslashes without escaping.

javascript
const winPath = String.raw`C:\Users\Alice\Documents`
// 'C:\\Users\\Alice\\Documents'

Back to index


T-047: Unicode normalize

Answer:

Note

NFC combines composed characters consistently.

javascript
const composed = 'e\u0301'
composed.normalize('NFC') // 'é' (single code point)

Back to index


T-048: Parse query string

Answer:

Note

URLSearchParams + Object.fromEntries.

javascript
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' }

Back to index


Quick reference — method by task

TasksPrimary APIs
T-001 – T-005literals, .length, charAt, .at(), immutability
T-006 – T-013toUpperCase, trim, includes, indexOf, slice, replace, replaceAll
T-014 – T-020split, join, padStart, repeat, charCodeAt, templates
T-021 – T-040trim, slug, title case, truncate, highlight, localeCompare
T-041 – T-048regex, matchAll, tagged templates, String.raw, URLSearchParams

Interview tip: Practice explaining T-005 (immutability), T-011 (slice vs substring), and T-019 (emoji length) aloud.

Share this article

XLinkedInFacebook
Kazi Rahamatullah

Written by

Kazi Rahamatullah

FullStack Developer

X / TwitterGitHubLinkedIn

Subscribe to my newsletter

Stay up to date and get notified when I share new contents.

No spam ever, unsubscribe anytime