String Polyfills and Common Interview Methods in JavaScript
JavaScript provides us with a rich toolkit of built-in string methods. Need to find a word? Use .includes(). Need to duplicate text? Call .repeat(). In our day-to-day development, we treat these methods like magic black boxes: we put data in, and the correct result pops out.
But what happens when you sit down for a technical interview and the interviewer asks: "Can you write your own version of .includes() without using any built-in string search methods?"
Suddenly, the black box is open. To pass the test, you have to prove you understand exactly how the JavaScript engine parses and manipulates text. Let's explore why developers write polyfills, the logic behind common string utilities, and how to tackle these classic interview questions.
What is a Polyfill? (And Why Do Interviewers Love Them?)
A polyfill is a piece of code (usually JavaScript on the web) used to provide modern functionality on older browsers that do not natively support it. For example, if an ancient browser didn't know what String.prototype.includes was, developers would write a custom function and attach it to the String prototype so their modern code wouldn't crash.
Today, browsers update automatically, so we rarely write string polyfills for compatibility. However, interviewers love asking you to write polyfills because it tests three crucial skills:
Algorithmic Thinking: Can you break a high-level task down into fundamental loops and conditions?
Edge Case Awareness: Do you remember to handle negative numbers, empty strings, or invalid data types?
Language Mechanics: Do you understand how the
thiskeyword behaves when attached to a prototype?
Let's look at how to implement a few common string methods from scratch.
Deep Dive 1: Recreating String.prototype.repeat()
The .repeat(count) method takes a number and returns a new string containing the original text repeated that many times.
The Built-in Behavior:
"abc".repeat(3); // Returns: "abcabcabc"
The Problem-Solving Logic: To build this, we need to handle a few things:
We need access to the string itself (using the
thiskeyword).We need to loop
counttimes, appending the string to a result variable.The Edge Cases: What if the count is negative? What if it is
Infinity? The official JavaScript specification throws aRangeErrorin these cases, so our polyfill must do the same.
The Implementation:
String.prototype.myRepeat = function(count) {
// Edge Case 1: Count cannot be negative
if (count < 0) {
throw new RangeError("Invalid count value");
}
// Edge Case 2: Count cannot be Infinity
if (count === Infinity) {
throw new RangeError("Invalid count value");
}
// Convert the count to an integer (in case a float was passed)
count = Math.floor(count);
let result = "";
let stringToRepeat = this; // 'this' points to the string calling the method
// Core Logic: Simply append the string to the result 'count' times
for (let i = 0; i < count; i++) {
result += stringToRepeat;
}
return result;
};
console.log("ha".myRepeat(3)); // Output: "hahaha"
Deep Dive 2: Recreating String.prototype.includes()
The .includes(searchString) method checks if a specific sequence of characters exists within the string, returning true or false.
The Built-in Behavior:
"hello world".includes("world"); // Returns: true
The Problem-Solving Logic: How do we find a needle in a haystack without using .indexOf() or .search()? We have to use a "sliding window" approach.
We loop through the main string one character at a time.
At each character, we check: Does this character, and the ones immediately following it, match our target word?
If we find a complete match, return
true. If we finish the loop without a match, returnfalse.
The Implementation:
String.prototype.myIncludes = function(searchString) {
const target = String(searchString); // Ensure it's a string
const mainString = this;
// If the target is longer than the string, it can't possibly fit
if (target.length > mainString.length) return false;
// Loop through the main string
// We stop early (mainString.length - target.length) because there isn't
// enough room left for the target string to fit at the end.
for (let i = 0; i <= mainString.length - target.length; i++) {
let match = true;
// Check the next characters against the target string
for (let j = 0; j < target.length; j++) {
if (mainString[i + j] !== target[j]) {
match = false; // The moment a character doesn't match, break the inner loop
break;
}
}
// If the inner loop finished and match is still true, we found it!
if (match) return true;
}
return false; // Target was not found
};
console.log("javascript".myIncludes("script")); // Output: true
console.log("javascript".myIncludes("python")); // Output: false
The Importance of Understanding Built-in Behavior
When preparing for interviews, it is easy to focus only on solving complex LeetCode algorithms. However, a deep understanding of JavaScript's native string utilities demonstrates a maturity in your engineering skills.
By practicing polyfills, you aren't just memorizing trivia. You are learning how to handle pointer management in loops, how to safely attach methods to prototypes, and how to rigorously validate inputs—all of which are critical skills for writing robust, production-level code.
The next time you use a built-in array or string method, take a moment to ask yourself: "Could I build this from scratch?" If the answer is yes, you are ready for the interview.