JavaScript Tutorial

Strings and String Methods in JavaScript: Complete Guide

Master JavaScript strings and all built-in string methods including slice, split, replace, includes, indexOf, toUpperCase, trim, padStart and more with real-world examples and best practices.

Welcome back! šŸ‘‹ In the previous lesson, you mastered arrow functions. Now we're kicking off the Working with Data Structures section with the most fundamental data type you'll work with every day — Strings!

Strings are everywhere — usernames, messages, URLs, form inputs, API responses, file paths, and more. JavaScript comes packed with powerful built-in string methods that let you search, transform, extract, and format text with ease.

By the end of this lesson, you'll never struggle with string manipulation again. Let's dive in!


What is a String?

A string is a sequence of characters used to represent text. In JavaScript, strings are primitive values — but they come with a rich set of built-in methods you can call on them.

let name    = "Mihir";           // double quotes
let city    = 'Mumbai';          // single quotes
let message = `Hello, World!`;   // template literal (backticks)

All three are valid strings in JavaScript. We'll cover template literals in depth in the next lesson.


String Basics

String Length

let name = "JavaScript";
console.log(name.length); // 10

Accessing Characters

Strings are zero-indexed — the first character is at index 0.

let lang = "JavaScript";

console.log(lang[0]);          // "J"
console.log(lang[4]);          // "S"
console.log(lang[lang.length - 1]); // "t" (last character)

Strings are Immutable

You can read characters but you cannot change them directly.

let name = "Mihir";
name[0] = "P";         // āŒ Does nothing — strings are immutable
console.log(name);     // "Mihir" — unchanged

// āœ… Create a new string instead
let newName = "P" + name.slice(1);
console.log(newName);  // "Pihir"

String Concatenation

Using + Operator

let firstName = "Mihir";
let lastName  = "Shah";
let fullName  = firstName + " " + lastName;

console.log(fullName); // "Mihir Shah"

Using Template Literals (Recommended āœ…)

let firstName = "Mihir";
let lastName  = "Shah";
let fullName  = `${firstName} ${lastName}`;

console.log(fullName); // "Mihir Shah"

We'll go deeper on template literals in the next lesson — but always prefer them over + for readability.


Case Methods

toUpperCase() and toLowerCase()

let text = "Hello, JavaScript!";

console.log(text.toUpperCase()); // "HELLO, JAVASCRIPT!"
console.log(text.toLowerCase()); // "hello, javascript!"

Real-World Use — Case-Insensitive Comparison

let userInput = "JAVASCRIPT";
let expected  = "javascript";

// āŒ Case-sensitive — fails
console.log(userInput === expected); // false

// āœ… Normalize both to lowercase before comparing
console.log(userInput.toLowerCase() === expected.toLowerCase()); // true

Searching Methods

includes() — Does the string contain a value?

Returns true or false.

let sentence = "JavaScript is awesome!";

console.log(sentence.includes("JavaScript")); // true
console.log(sentence.includes("Python"));     // false
console.log(sentence.includes("is"));         // true

startsWith() and endsWith()

let url = "https://www.example.com";

console.log(url.startsWith("https")); // true
console.log(url.startsWith("http://"));// false
console.log(url.endsWith(".com"));     // true
console.log(url.endsWith(".org"));     // false

indexOf() — Find the position of a substring

Returns the index of the first occurrence, or -1 if not found.

let text = "Hello, JavaScript! JavaScript is great.";

console.log(text.indexOf("JavaScript"));  // 7
console.log(text.indexOf("Python"));      // -1
console.log(text.indexOf("JavaScript", 10)); // 19 (search from index 10)

lastIndexOf() — Find the last occurrence

let text = "Hello, JavaScript! JavaScript is great.";

console.log(text.lastIndexOf("JavaScript")); // 19 (last occurrence)

Practical — Check if URL is Secure

function isSecureUrl(url) {
  return url.startsWith("https://");
}

console.log(isSecureUrl("https://example.com")); // true
console.log(isSecureUrl("http://example.com"));  // false

Extracting Methods

slice(start, end) — Extract a portion

Returns characters from start up to (but not including) end. Accepts negative indexes.

let text = "JavaScript";
//          0123456789

console.log(text.slice(0, 4));   // "Java"
console.log(text.slice(4));      // "Script" (to end)
console.log(text.slice(-6));     // "Script" (6 from end)
console.log(text.slice(0, -6));  // "Java"  (all except last 6)

substring(start, end) — Similar to slice

Like slice but does not support negative indexes.

let text = "JavaScript";

console.log(text.substring(0, 4)); // "Java"
console.log(text.substring(4));    // "Script"

slice vs substring

let text = "JavaScript";

// Negative index — slice supports it, substring does not
console.log(text.slice(-6));       // "Script" āœ…
console.log(text.substring(-6));   // "JavaScript" — treats negative as 0

// āœ… Prefer slice — it handles negative indexes correctly

charAt(index) — Get character at a position

let text = "Hello";

console.log(text.charAt(0));  // "H"
console.log(text.charAt(4));  // "o"
console.log(text[0]);         // "H" — same result using bracket notation

Modifying Methods

replace() — Replace first occurrence

let text = "I love JavaScript. JavaScript is great!";

console.log(text.replace("JavaScript", "Python"));
// "I love Python. JavaScript is great!" — only first replaced

replaceAll() — Replace all occurrences

let text = "I love JavaScript. JavaScript is great!";

console.log(text.replaceAll("JavaScript", "Python"));
// "I love Python. Python is great!" āœ…

trim(), trimStart(), trimEnd() — Remove whitespace

let messy = "   Hello, World!   ";

console.log(messy.trim());       // "Hello, World!"
console.log(messy.trimStart());  // "Hello, World!   "
console.log(messy.trimEnd());    // "   Hello, World!"

Real-World Use — Clean User Input

function cleanInput(input) {
  return input.trim().toLowerCase();
}

console.log(cleanInput("  MIHIR  ")); // "mihir"
console.log(cleanInput("  JavaScript  ")); // "javascript"

repeat() — Repeat a string

let dash  = "-".repeat(20);
let stars = "⭐".repeat(5);

console.log(dash);   // "--------------------"
console.log(stars);  // "⭐⭐⭐⭐⭐"

Padding Methods

padStart(length, padString) — Pad from the left

let num = "42";

console.log(num.padStart(5, "0")); // "00042"
console.log(num.padStart(5, "*")); // "***42"

padEnd(length, padString) — Pad from the right

let label = "Name";

console.log(label.padEnd(10, ".")); // "Name......"

Real-World Use — Format a Receipt

let items = [
  { name: "Laptop",  price: 55000 },
  { name: "Mouse",   price: 800   },
  { name: "Bag",     price: 1200  },
];

console.log("=".repeat(30));
for (let item of items) {
  console.log(item.name.padEnd(15) + `₹${item.price}`.padStart(10));
}
console.log("=".repeat(30));
// Output:
// ==============================
// Laptop          ₹55000
// Mouse            ₹800
// Bag             ₹1200
// ==============================

Splitting and Joining

split(separator) — String to Array

Splits a string into an array of substrings.

let csv   = "Mihir,Priya,Rahul,Sara";
let names = csv.split(",");

console.log(names);        // ["Mihir", "Priya", "Rahul", "Sara"]
console.log(names.length); // 4
// Split into individual characters
let word  = "Hello";
let chars = word.split("");
console.log(chars); // ["H", "e", "l", "l", "o"]

// Split into words
let sentence = "JavaScript is awesome";
let words    = sentence.split(" ");
console.log(words); // ["JavaScript", "is", "awesome"]

join() — Array to String (opposite of split)

let words = ["JavaScript", "is", "awesome"];

console.log(words.join(" "));  // "JavaScript is awesome"
console.log(words.join("-"));  // "JavaScript-is-awesome"
console.log(words.join(""));   // "JavaScriptisawesome"

Real-World Use — Slugify a Title

function slugify(title) {
  return title
    .toLowerCase()
    .trim()
    .split(" ")
    .join("-");
}

console.log(slugify("Hello World"));              // "hello-world"
console.log(slugify("  JavaScript Is Amazing  ")); // "javascript-is-amazing"
console.log(slugify("Working With Data Structures")); // "working-with-data-structures"

Real-World Examples

Example 1: Username Validator

function validateUsername(username) {
  let cleaned = username.trim();

  if (cleaned.length < 3) {
    return "āŒ Username too short (min 3 characters)";
  }
  if (cleaned.length > 20) {
    return "āŒ Username too long (max 20 characters)";
  }
  if (cleaned.includes(" ")) {
    return "āŒ Username cannot contain spaces";
  }
  return `āœ… Valid username: "${cleaned}"`;
}

console.log(validateUsername("  mi  "));         // āŒ too short
console.log(validateUsername("Mihir Shah"));     // āŒ contains space
console.log(validateUsername("mihir_dev_2024")); // āœ… valid

Example 2: Format a Phone Number

function formatPhone(raw) {
  let digits = raw.trim().replace(/\D/g, ""); // keep digits only

  if (digits.length !== 10) {
    return "āŒ Invalid phone number";
  }

  return `+91 ${digits.slice(0, 5)}-${digits.slice(5)}`;
}

console.log(formatPhone("9876543210"));    // +91 98765-43210
console.log(formatPhone(" 98765 43210 ")); // +91 98765-43210
console.log(formatPhone("123"));           // āŒ Invalid phone number

Example 3: Truncate Long Text

function truncate(text, maxLength, suffix = "...") {
  if (text.length <= maxLength) return text;
  return text.slice(0, maxLength - suffix.length).trimEnd() + suffix;
}

let title = "Working with Data Structures in JavaScript";

console.log(truncate(title, 20));     // "Working with Data..."
console.log(truncate(title, 30));     // "Working with Data Structure..."
console.log(truncate(title, 100));    // Full title — no truncation

Example 4: Parse a CSV Line

function parseCSV(line) {
  let fields = line.split(",").map(field => field.trim());

  return {
    name:  fields[0],
    email: fields[1],
    role:  fields[2],
    city:  fields[3],
  };
}

let row = "  Mihir Shah , mihir@example.com , Admin , Mumbai ";
let user = parseCSV(row);

console.log(user);
// { name: 'Mihir Shah', email: 'mihir@example.com', role: 'Admin', city: 'Mumbai' }

Example 5: Capitalize Each Word

function titleCase(sentence) {
  return sentence
    .toLowerCase()
    .split(" ")
    .map(word => word.charAt(0).toUpperCase() + word.slice(1))
    .join(" ");
}

console.log(titleCase("hello world"));                    // "Hello World"
console.log(titleCase("working with data structures"));   // "Working With Data Structures"
console.log(titleCase("jAVAsCRIPT iS aWESOME"));          // "Javascript Is Awesome"

String Methods Cheat Sheet

MethodWhat it doesExample
lengthNumber of characters"Hello".length → 5
toUpperCase()All uppercase"hi".toUpperCase() → "HI"
toLowerCase()All lowercase"HI".toLowerCase() → "hi"
includes(str)Contains a substring?"Hello".includes("ell") → true
startsWith(str)Starts with?"Hello".startsWith("He") → true
endsWith(str)Ends with?"Hello".endsWith("lo") → true
indexOf(str)First index of"Hello".indexOf("l") → 2
lastIndexOf(str)Last index of"Hello".lastIndexOf("l") → 3
slice(s, e)Extract part"Hello".slice(1, 3) → "el"
replace(a, b)Replace first"Hi Hi".replace("Hi","Hey") → "Hey Hi"
replaceAll(a, b)Replace all"Hi Hi".replaceAll("Hi","Hey") → "Hey Hey"
trim()Remove whitespace both ends" Hi ".trim() → "Hi"
split(sep)String to array"a,b".split(",") → ["a","b"]
repeat(n)Repeat string"ab".repeat(3) → "ababab"
padStart(n, c)Pad left"5".padStart(3,"0") → "005"
padEnd(n, c)Pad right"5".padEnd(3,"0") → "500"
charAt(i)Char at index"Hello".charAt(1) → "e"

Common Mistakes

Mistake 1: Using == to Compare Strings

// āŒ Loose equality — unexpected results
console.log("5" == 5);    // true (type coercion!)

// āœ… Always use === for strings
console.log("5" === 5);   // false āœ…
console.log("hi" === "hi"); // true āœ…

Mistake 2: Forgetting trim() on User Input

let input = "  mihir  ";

// āŒ Spaces cause false negatives
console.log(input === "mihir"); // false āŒ

// āœ… Always trim user input before comparison
console.log(input.trim() === "mihir"); // true āœ…

Mistake 3: replace() Only Replaces the First Match

let text = "cat and cat and cat";

// āŒ Only replaces first "cat"
console.log(text.replace("cat", "dog")); // "dog and cat and cat"

// āœ… Use replaceAll() for all occurrences
console.log(text.replaceAll("cat", "dog")); // "dog and dog and dog" āœ…

Mistake 4: Mutating a String Directly

let name = "mihir";

// āŒ Strings are immutable — this does nothing
name[0] = "M";
console.log(name); // "mihir" — unchanged!

// āœ… Create a new string
name = name[0].toUpperCase() + name.slice(1);
console.log(name); // "Mihir" āœ…

Practical Exercise

Create a file called strings.js:

// šŸŽÆ Strings Practice

// 1. String analyzer
function analyzeString(str) {
  console.log(`\n=== Analyzing: "${str}" ===`);
  console.log(`Length:       ${str.length}`);
  console.log(`Uppercase:    ${str.toUpperCase()}`);
  console.log(`Lowercase:    ${str.toLowerCase()}`);
  console.log(`Reversed:     ${str.split("").reverse().join("")}`);
  console.log(`Word count:   ${str.trim().split(" ").filter(w => w).length}`);
  console.log(`Has spaces:   ${str.includes(" ")}`);
  console.log(`First char:   ${str[0]}`);
  console.log(`Last char:    ${str[str.length - 1]}`);
}

analyzeString("Hello World");
analyzeString("JavaScript");
analyzeString("  Working with Strings  ");


// 2. Email validator
function validateEmail(email) {
  let cleaned = email.trim().toLowerCase();
  let hasAt   = cleaned.includes("@");
  let hasDot  = cleaned.includes(".");
  let atIndex = cleaned.indexOf("@");
  let dotAfterAt = cleaned.lastIndexOf(".") > atIndex;

  if (hasAt && hasDot && dotAfterAt && atIndex > 0) {
    return `āœ… Valid email: ${cleaned}`;
  }
  return `āŒ Invalid email: "${email}"`;
}

console.log("\n=== Email Validator ===");
console.log(validateEmail("mihir@example.com"));
console.log(validateEmail("not-an-email"));
console.log(validateEmail("missing@dot"));
console.log(validateEmail("  MIHIR@EXAMPLE.COM  "));


// 3. Password strength checker
function checkPassword(password) {
  console.log(`\nPassword: "${password}"`);

  let hasUpper  = password !== password.toLowerCase();
  let hasLower  = password !== password.toUpperCase();
  let hasDigit  = "0123456789".split("").some(d => password.includes(d));
  let longEnough = password.length >= 8;

  let strength = [hasUpper, hasLower, hasDigit, longEnough]
    .filter(Boolean).length;

  let label = strength === 4 ? "šŸ’Ŗ Strong"
            : strength === 3 ? "🟔 Medium"
            : "šŸ”“ Weak";

  console.log(`  Uppercase:  ${hasUpper  ? "āœ…" : "āŒ"}`);
  console.log(`  Lowercase:  ${hasLower  ? "āœ…" : "āŒ"}`);
  console.log(`  Digit:      ${hasDigit  ? "āœ…" : "āŒ"}`);
  console.log(`  Length 8+:  ${longEnough ? "āœ…" : "āŒ"}`);
  console.log(`  Strength:   ${label}`);
}

console.log("\n=== Password Checker ===");
checkPassword("abc");
checkPassword("password");
checkPassword("Pass1234");


// 4. Format product tags
function formatTags(tagString) {
  return tagString
    .split(",")
    .map(tag => tag.trim().toLowerCase().replaceAll(" ", "-"))
    .filter(tag => tag.length > 0)
    .join(" | ");
}

console.log("\n=== Tag Formatter ===");
console.log(formatTags("JavaScript, Web Dev, Front End, ES6"));
// javascript | web-dev | front-end | es6

Run it:

node strings.js

Expected Output:

=== Analyzing: "Hello World" ===
Length:       11
Uppercase:    HELLO WORLD
Lowercase:    hello world
Reversed:     dlroW olleH
Word count:   2
Has spaces:   true
First char:   H
Last char:    d

=== Email Validator ===
āœ… Valid email: mihir@example.com
āŒ Invalid email: "not-an-email"
āŒ Invalid email: "missing@dot"
āœ… Valid email: mihir@example.com

=== Password Checker ===
Password: "Pass1234"
  Uppercase:  āœ…
  Lowercase:  āœ…
  Digit:      āœ…
  Length 8+:  āœ…
  Strength:   šŸ’Ŗ Strong

=== Tag Formatter ===
javascript | web-dev | front-end | es6

Key Takeaways

Congratulations! šŸŽ‰ You now have a complete toolkit for working with strings in JavaScript.

āœ… Strings are immutable — methods always return a new string, they never change the original.

āœ… Case methods: toUpperCase(), toLowerCase() — always normalize case before comparing.

āœ… Searching: includes(), startsWith(), endsWith(), indexOf(), lastIndexOf().

āœ… Extracting: slice(start, end) — supports negative indexes, preferred over substring().

āœ… Modifying: replace() replaces first match only — use replaceAll() for all occurrences.

āœ… Whitespace: Always trim() user input before processing or comparing.

āœ… Splitting: split(sep) → array. join(sep) → string. Used together constantly.

āœ… Padding: padStart() and padEnd() for formatting numbers and table-style output.


Best Practices

  1. āœ… Always trim() user input before validating or storing
  2. āœ… Use toLowerCase() or toUpperCase() before comparing strings
  3. āœ… Prefer slice() over substring() — it handles negative indexes correctly
  4. āœ… Use replaceAll() when you want to replace every occurrence, not just the first
  5. āœ… Prefer template literals over + concatenation for readability
  6. āœ… Use split() + map() + join() for powerful string transformations
  7. āœ… Remember — strings are immutable — always assign the result to a variable
  8. āœ… Use includes() instead of indexOf() !== -1 — it reads more naturally

What's Next?

Great work! šŸŽ‰ You now have a complete string manipulation toolkit.

Next up, let's explore Template Literals → — the modern, powerful way to work with strings in JavaScript. Multi-line strings, embedded expressions, tagged templates and more!

Let's keep going! šŸ’Ŗ