DEV Community

Cover image for String Polyfills and Common Interview Methods in JavaScript
Pratham
Pratham

Posted on

String Polyfills and Common Interview Methods in JavaScript

Understanding how string methods work under the hood — and building them yourself.


Here's something that changed how I think about JavaScript: anyone can use .trim() or .includes(). You call the method, it works, you move on. But can you build it from scratch? Can you explain what happens inside when you call .split() or .repeat()?

That's exactly what interviewers want to know. Not whether you've memorized the API, but whether you understand the logic behind it. And the best way to prove that? Write the method yourself — a polyfill.

In the ChaiCode Web Dev Cohort 2026, this shift from "using tools" to "understanding tools" was a turning point. Let me walk you through the most common string methods, how they work conceptually, and how to build your own versions.


What Are String Methods?

String methods are built-in functions that every string in JavaScript comes with. They let you manipulate, search, transform, and inspect text without writing manual loops.

const name = "  Pratham Bhardwaj  ";

console.log(name.trim()); // "Pratham Bhardwaj"
console.log(name.toUpperCase()); // "  PRATHAM BHARDWAJ  "
console.log(name.includes("Pratham")); // true
console.log(name.split(" ")); // ["", "", "Pratham", "Bhardwaj", "", ""]
Enter fullscreen mode Exit fullscreen mode

One line, one method, one result. But what's happening inside each of these calls? That's what we're going to explore.

Strings Are Immutable

Before we go further, remember this: strings in JavaScript cannot be changed. Every string method returns a new string — the original stays untouched.

const greeting = "hello";
const shouted = greeting.toUpperCase();

console.log(greeting); // "hello" — unchanged
console.log(shouted); // "HELLO" — new string
Enter fullscreen mode Exit fullscreen mode

This is important for polyfills — your implementations should always return new values, never mutate the input.


Why Do Developers Write Polyfills?

A polyfill is a piece of code that provides the functionality of a newer feature in environments that don't natively support it. But beyond browser compatibility, writing polyfills serves two bigger purposes:

1. Deep Understanding

When you build .trim() from scratch, you have to understand exactly what it does: strip whitespace from both ends, leave everything in the middle alone. You can't fake that understanding.

2. Interview Preparation

"Implement String.prototype.includes" is a real interview question. Interviewers don't care that the method already exists. They want to see:

  • Can you break a problem into steps?
  • Do you understand string indexing and iteration?
  • Can you handle edge cases?

The Polyfill Mental Model

Built-in method:   "hello".includes("ell")  →  true
                         ↓
                   (black box — you call it, it works)

Polyfill:          "hello".includes("ell")  →  true
                         ↓
                   Your code:
                   - Loop through each position
                   - At each position, check if substring matches
                   - If found, return true
                   - If loop ends, return false

Same input → same output. You just built the black box.
Enter fullscreen mode Exit fullscreen mode

Common String Methods — Concept + Polyfill

Let's go through the most commonly asked string methods. For each one, I'll explain what it does, show the built-in version, and then build it from scratch.

1. trim() — Remove Whitespace from Both Ends

What it does: Removes spaces, tabs, and newlines from the start and end of a string.

// Built-in
console.log("  hello  ".trim()); // "hello"
console.log("\t  hi \n".trim()); // "hi"
Enter fullscreen mode Exit fullscreen mode

Polyfill:

const myTrim = (str) => {
  let start = 0;
  let end = str.length - 1;

  // Move start forward past whitespace
  while (start <= end && str[start] === " ") {
    start++;
  }

  // Move end backward past whitespace
  while (end >= start && str[end] === " ") {
    end--;
  }

  // Extract the substring between start and end (inclusive)
  return str.slice(start, end + 1);
};

console.log(myTrim("  hello  ")); // "hello"
console.log(myTrim("   ")); // ""
console.log(myTrim("no spaces")); // "no spaces"
Enter fullscreen mode Exit fullscreen mode

How it works: Two pointers — one from the left, one from the right — move inward past whitespace characters. Whatever's between them is the trimmed result.

Input:   "   hello   "
          ↑         ↑
        start      end

Step 1:  start moves right past spaces → lands on 'h'
Step 2:  end moves left past spaces → lands on 'o'

Result:  str.slice(start, end + 1) → "hello"
Enter fullscreen mode Exit fullscreen mode

2. includes() — Check If a Substring Exists

What it does: Returns true if the string contains the specified substring, false otherwise.

// Built-in
console.log("JavaScript".includes("Script")); // true
console.log("JavaScript".includes("Python")); // false
Enter fullscreen mode Exit fullscreen mode

Polyfill:

const myIncludes = (str, target) => {
  if (target.length > str.length) return false;

  for (let i = 0; i <= str.length - target.length; i++) {
    if (str.slice(i, i + target.length) === target) {
      return true;
    }
  }

  return false;
};

console.log(myIncludes("JavaScript", "Script")); // true
console.log(myIncludes("JavaScript", "Python")); // false
console.log(myIncludes("hello", "")); // true (empty string is always found)
Enter fullscreen mode Exit fullscreen mode

How it works: Slide a window of target.length across the string. At each position, extract a chunk and compare it to the target.

String:  "JavaScript"
Target:  "Script"  (length: 6)

Position 0:  "JavaSc" === "Script"?  No
Position 1:  "avaSci" === "Script"?  No
Position 2:  "vaScrip" — wait, let me recalculate
Position 4:  "Script" === "Script"?  ✅ Yes → return true
Enter fullscreen mode Exit fullscreen mode

3. repeat() — Repeat a String N Times

What it does: Returns a new string with the original repeated n times.

// Built-in
console.log("ha".repeat(3)); // "hahaha"
console.log("".repeat(5)); // "⭐⭐⭐⭐⭐"
Enter fullscreen mode Exit fullscreen mode

Polyfill:

const myRepeat = (str, count) => {
  if (count <= 0) return "";

  let result = "";
  for (let i = 0; i < count; i++) {
    result += str;
  }
  return result;
};

console.log(myRepeat("ha", 3)); // "hahaha"
console.log(myRepeat("abc", 0)); // ""
console.log(myRepeat("-", 10)); // "----------"
Enter fullscreen mode Exit fullscreen mode

How it works: Start with an empty string. Loop count times, concatenating the original string each time.

myRepeat("ha", 3):

  i=0:  result = "" + "ha"     → "ha"
  i=1:  result = "ha" + "ha"   → "haha"
  i=2:  result = "haha" + "ha" → "hahaha"

  Return: "hahaha"
Enter fullscreen mode Exit fullscreen mode

4. startsWith() and endsWith() — Check Beginning/End

What they do: Check if a string starts or ends with a given substring.

// Built-in
console.log("Pratham".startsWith("Pra")); // true
console.log("Pratham".endsWith("ham")); // true
Enter fullscreen mode Exit fullscreen mode

Polyfills:

const myStartsWith = (str, target) => {
  if (target.length > str.length) return false;
  return str.slice(0, target.length) === target;
};

const myEndsWith = (str, target) => {
  if (target.length > str.length) return false;
  return str.slice(str.length - target.length) === target;
};

console.log(myStartsWith("Pratham", "Pra")); // true
console.log(myStartsWith("Pratham", "ham")); // false
console.log(myEndsWith("Pratham", "ham")); // true
console.log(myEndsWith("Pratham", "Pra")); // false
Enter fullscreen mode Exit fullscreen mode

How it works: Extract a chunk from the beginning (or end) with the same length as the target. Compare directly.

myStartsWith("Pratham", "Pra"):
  str.slice(0, 3) → "Pra"
  "Pra" === "Pra" → true ✅

myEndsWith("Pratham", "ham"):
  str.slice(7 - 3) → str.slice(4) → "ham"
  "ham" === "ham" → true ✅
Enter fullscreen mode Exit fullscreen mode

5. indexOf() — Find the Position of a Substring

What it does: Returns the index of the first occurrence of a substring. Returns -1 if not found.

// Built-in
console.log("JavaScript".indexOf("Script")); // 4
console.log("JavaScript".indexOf("Python")); // -1
Enter fullscreen mode Exit fullscreen mode

Polyfill:

const myIndexOf = (str, target) => {
  if (target === "") return 0;
  if (target.length > str.length) return -1;

  for (let i = 0; i <= str.length - target.length; i++) {
    if (str.slice(i, i + target.length) === target) {
      return i;
    }
  }

  return -1;
};

console.log(myIndexOf("JavaScript", "Script")); // 4
console.log(myIndexOf("JavaScript", "Java")); // 0
console.log(myIndexOf("JavaScript", "Python")); // -1
console.log(myIndexOf("hello hello", "hello")); // 0 (first occurrence)
Enter fullscreen mode Exit fullscreen mode

Notice how similar this is to includes()? The logic is nearly identical — the only difference is that includes() returns true/false while indexOf() returns the position.


6. charAt() — Get Character at Index

What it does: Returns the character at a given index.

// Built-in
console.log("Pratham".charAt(0)); // "P"
console.log("Pratham".charAt(3)); // "t"
Enter fullscreen mode Exit fullscreen mode

Polyfill:

const myCharAt = (str, index) => {
  if (index < 0 || index >= str.length) return "";
  return str[index];
};

console.log(myCharAt("Pratham", 0)); // "P"
console.log(myCharAt("Pratham", 6)); // "m"
console.log(myCharAt("Pratham", 10)); // ""
Enter fullscreen mode Exit fullscreen mode

This one's almost too simple — but interviewers use it as a warm-up before harder questions.


Common Interview String Problems

Beyond polyfills, these are the string problems that show up constantly in interviews:

1. Reverse a String

const reverseString = (str) => {
  let reversed = "";
  for (let i = str.length - 1; i >= 0; i--) {
    reversed += str[i];
  }
  return reversed;
};

console.log(reverseString("hello")); // "olleh"
console.log(reverseString("JavaScript")); // "tpircSavaJ"
Enter fullscreen mode Exit fullscreen mode

Or the one-liner:

const reverseString = (str) => str.split("").reverse().join("");
Enter fullscreen mode Exit fullscreen mode

Interview tip: Know both approaches. The loop shows you understand the logic. The one-liner shows you know the language.

2. Check If a String Is a Palindrome

const isPalindrome = (str) => {
  const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, "");
  let left = 0;
  let right = cleaned.length - 1;

  while (left < right) {
    if (cleaned[left] !== cleaned[right]) return false;
    left++;
    right--;
  }

  return true;
};

console.log(isPalindrome("racecar")); // true
console.log(isPalindrome("Race Car")); // true
console.log(isPalindrome("hello")); // false
Enter fullscreen mode Exit fullscreen mode
"racecar" — check from both ends:

  r ← → r  ✅
   a ← → a  ✅
    c ← → c  ✅
     e (center — done)

Result: true (it's a palindrome)
Enter fullscreen mode Exit fullscreen mode

3. Count Character Occurrences

const charCount = (str) => {
  const counts = {};
  for (const char of str) {
    counts[char] = (counts[char] || 0) + 1;
  }
  return counts;
};

console.log(charCount("hello"));
// { h: 1, e: 1, l: 2, o: 1 }

console.log(charCount("javascript"));
// { j: 1, a: 2, v: 1, s: 1, c: 1, r: 1, i: 1, p: 1, t: 1 }
Enter fullscreen mode Exit fullscreen mode

4. Capitalize First Letter of Each Word

const capitalizeWords = (str) => {
  return str
    .split(" ")
    .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
    .join(" ");
};

console.log(capitalizeWords("hello world")); // "Hello World"
console.log(capitalizeWords("javaScript is FUN")); // "Javascript Is Fun"
Enter fullscreen mode Exit fullscreen mode

5. Check If Two Strings Are Anagrams

const isAnagram = (str1, str2) => {
  const normalize = (s) => s.toLowerCase().split("").sort().join("");
  return normalize(str1) === normalize(str2);
};

console.log(isAnagram("listen", "silent")); // true
console.log(isAnagram("hello", "world")); // false
console.log(isAnagram("Dormitory", "Dirty Room")); // false (spaces matter here)
Enter fullscreen mode Exit fullscreen mode

Why Understanding Built-In Behavior Matters

Let me be direct about this: knowing how to use string methods isn't enough anymore.

In interviews, knowing that .includes() exists gets you zero points. But explaining that it works by sliding a window across the string and comparing substrings at each position? That shows you think like a developer.

Here's what building polyfills teaches you:

Skill How Polyfills Build It
String indexing You manually access str[i] and work with positions
Loop construction You build for loops with correct boundaries
Edge case thinking Empty strings, out-of-bounds indexes, targets longer than source
Algorithm design Sliding window, two pointers, accumulation patterns
Problem decomposition Breaking "trim this string" into concrete, implementable steps

These aren't just interview skills — they're engineering skills. Every complex feature you'll ever build requires breaking problems into steps, handling edge cases, and understanding what your tools are doing under the surface.


String Processing Flow — The General Pattern

Most string polyfills follow the same general flow:

┌─────────────────────┐
│   Receive input      │
│   (string + args)    │
└──────────┬──────────┘
           ↓
┌─────────────────────┐
│   Handle edge cases  │
│   (empty, null, etc) │
└──────────┬──────────┘
           ↓
┌─────────────────────┐
│   Iterate through    │
│   the string         │
│   (char by char or   │
│    window by window) │
└──────────┬──────────┘
           ↓
┌─────────────────────┐
│   Apply logic at     │
│   each position      │
│   (compare, count,   │
│    accumulate)        │
└──────────┬──────────┘
           ↓
┌─────────────────────┐
│   Return result      │
│   (new string, index,│
│    boolean)           │
└─────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Once you see this pattern, every string polyfill becomes a variation of the same structure. The only thing that changes is the logic in the middle.


Let's Practice: Hands-On Assignment

Part 1: Build myTrim()

// Implement your own trim function
const myTrim = (str) => {
  let start = 0;
  let end = str.length - 1;

  while (start <= end && str[start] === " ") start++;
  while (end >= start && str[end] === " ") end--;

  return str.slice(start, end + 1);
};

// Test it
console.log(myTrim("   hello world   ")); // "hello world"
console.log(myTrim("no spaces")); // "no spaces"
console.log(myTrim("     ")); // ""
Enter fullscreen mode Exit fullscreen mode

Part 2: Build myIncludes()

const myIncludes = (str, target) => {
  for (let i = 0; i <= str.length - target.length; i++) {
    if (str.slice(i, i + target.length) === target) return true;
  }
  return false;
};

// Test it
console.log(myIncludes("ChaiCode", "Chai")); // true
console.log(myIncludes("ChaiCode", "Tea")); // false
Enter fullscreen mode Exit fullscreen mode

Part 3: Reverse a String Without Built-In Methods

const myReverse = (str) => {
  let result = "";
  for (let i = str.length - 1; i >= 0; i--) {
    result += str[i];
  }
  return result;
};

console.log(myReverse("Pratham")); // "mahtarP"
console.log(myReverse("12345")); // "54321"
Enter fullscreen mode Exit fullscreen mode

Part 4: Count Vowels in a String

const countVowels = (str) => {
  const vowels = "aeiouAEIOU";
  let count = 0;

  for (const char of str) {
    if (vowels.includes(char)) count++;
  }

  return count;
};

console.log(countVowels("Pratham Bhardwaj")); // 4
console.log(countVowels("JavaScript")); // 3
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  1. String methods are built-in functions that transform, search, and inspect text. They always return new values — strings are immutable.
  2. Polyfills are custom implementations of built-in features. Writing them proves you understand the logic, not just the API.
  3. Most string polyfills follow the same pattern: handle edge cases → iterate through the string → apply logic → return result.
  4. Common interview problems — reverse, palindrome, anagram, character count — all build on the same fundamental skills: string indexing, loops, and comparison.
  5. Understanding beats memorizing. Knowing how .includes() works makes you a better debugger, a better problem solver, and a stronger interview candidate.

Wrapping Up

There's a big difference between a developer who uses string methods and a developer who understands them. Polyfills bridge that gap. They force you to think about what actually happens when you call .trim() or .indexOf() — and that kind of thinking is exactly what separates junior developers from strong ones.

I'm building this depth of understanding through the ChaiCode Web Dev Cohort 2026 under Hitesh Chaudhary and Piyush Garg. Writing polyfills has been one of the most valuable exercises so far — not because I'll use them in production (I won't, the built-in methods are great), but because the process of building them made me a significantly better problem solver.

Connect with me on LinkedIn or visit PrathamDEV.in. More articles coming as I keep leveling up.

Happy coding! 🚀


Written by Pratham Bhardwaj | Web Dev Cohort 2026, ChaiCode

Top comments (0)