String Polyfills and Common Interview Methods in JavaScript

Every JavaScript developer has used toLowerCase(), trim(), or includes() without thinking twice. You call them, they work, you move on. But there is a moment in every developer's journey — usually in an interview room — when someone asks you to implement one from scratch.
Suddenly, the thing you have been using for months feels unfamiliar.
This article is about closing that gap. We are going to understand what string methods actually do under the hood, why writing your own versions matters, and walk through the exact problems that show up in JavaScript interviews over and over again.
What Are String Methods?
String methods are built-in functions that JavaScript gives you to work with text. They live on String.prototype, which means every string you create automatically has access to them.
const name = "nawazish";
console.log(name.toUpperCase()); // "NAWAZISH"
console.log(name.includes("waz")); // true
console.log(name.slice(0, 3)); // "naw"
These methods do not modify the original string. Strings in JavaScript are immutable — every operation returns a new string. This is an important detail that trips people up.
The reason you need to understand how these work internally is not because you will rewrite the standard library in production. It is because the logic behind them teaches you how to think about strings — character by character, index by index. That thinking is exactly what interviews test.
Why Do Developers Write Polyfills?
A polyfill is code you write to replicate the behavior of a built-in feature — usually because that feature does not exist in an older environment, or because you want to deeply understand how it works.
For example, String.prototype.trimStart() was introduced in ES2019. If you needed that behavior in a browser that predates ES2019, you would write your own version and attach it to the prototype.
if (!String.prototype.trimStart) {
String.prototype.trimStart = function () {
return this.replace(/^\s+/, '');
};
}
In interviews, when someone asks you to "implement X without using the built-in," they are essentially asking you to write a polyfill. It reveals whether you understand the behavior deeply or just know the method name.
String Processing Flow — The Visual
Input String: " hello world "
│
▼
┌─────────────────────┐
│ Process character │
│ by character │
│ using index │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Apply logic: │
│ trim / search / │
│ replace / slice │
└──────────┬──────────┘
│
▼
Output String: "hello world"
Most string operations are just loops under the hood — walking through characters, checking conditions, and building a new result. Once you see that, everything becomes much simpler.
Implementing Common String Methods
Let's build the most important ones from scratch.
1. myTrim() — Remove Whitespace from Both Ends
The built-in: " hello ".trim() → "hello"
String.prototype.myTrim = function () {
let start = 0;
let end = this.length - 1;
while (start <= end && this[start] === ' ') {
start++;
}
while (end >= start && this[end] === ' ') {
end--;
}
return this.slice(start, end + 1);
};
console.log(" hello world ".myTrim()); // "hello world"
Two pointers — one from the left, one from the right — both moving inward until they hit a non-space character. Then slice between them. That is the entire logic of trim().
2. myIncludes() — Check If a Substring Exists
The built-in: "javascript".includes("script") → true
String.prototype.myIncludes = function (searchStr) {
const len = this.length;
const searchLen = searchStr.length;
for (let i = 0; i <= len - searchLen; i++) {
if (this.slice(i, i + searchLen) === searchStr) {
return true;
}
}
return false;
};
console.log("javascript".myIncludes("script")); // true
console.log("javascript".myIncludes("java")); // true
console.log("javascript".myIncludes("python")); // false
We slide a window of the same length as the search string across the original string, checking for a match at each position. Simple sliding window logic.
3. myRepeat() — Repeat a String N Times
The built-in: "ha".repeat(3) → "hahaha"
String.prototype.myRepeat = function (count) {
if (count < 0) throw new RangeError('Invalid count value');
let result = '';
for (let i = 0; i < count; i++) {
result += this;
}
return result;
};
console.log("ha".myRepeat(3)); // "hahaha"
console.log("ab".myRepeat(4)); // "abababab"
4. myStartsWith() — Check If String Starts With a Value
The built-in: "hello".startsWith("hel") → true
String.prototype.myStartsWith = function (searchStr, position = 0) {
return this.slice(position, position + searchStr.length) === searchStr;
};
console.log("hello world".myStartsWith("hello")); // true
console.log("hello world".myStartsWith("world")); // false
console.log("hello world".myStartsWith("world", 6)); // true
Slice from the start and compare. One line of logic once you think it through.
5. myPadStart() — Pad a String from the Left
The built-in: "5".padStart(3, "0") → "005"
String.prototype.myPadStart = function (targetLength, padString = ' ') {
if (this.length >= targetLength) return String(this);
const padNeeded = targetLength - this.length;
let padding = '';
while (padding.length < padNeeded) {
padding += padString;
}
return padding.slice(0, padNeeded) + this;
};
console.log("5".myPadStart(3, "0")); // "005"
console.log("42".myPadStart(5, "0")); // "00042"
console.log("hi".myPadStart(6, "ab")); // "ababhi"
Calculate how much padding is needed, build the padding string by repeating the pad character, then trim to exact length and prepend.
Polyfill Behavior — The Visual
"5".myPadStart(3, "0")
targetLength = 3
this.length = 1
padNeeded = 3 - 1 = 2
Build padding:
"" → "0" → "00"
Slice to exact length:
"00".slice(0, 2) = "00"
Prepend to original:
"00" + "5" = "005"
Output: "005"
Common Interview String Problems
Beyond polyfills, these are the string problems that come up most frequently in JavaScript interviews:
Reverse a String
function reverseString(str) {
return str.split('').reverse().join('');
}
// Without built-ins:
function reverseString(str) {
let result = '';
for (let i = str.length - 1; i >= 0; i--) {
result += str[i];
}
return result;
}
console.log(reverseString("nawazish")); // "hsizawan"
Check If a String Is a Palindrome
function isPalindrome(str) {
const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
return cleaned === cleaned.split('').reverse().join('');
}
console.log(isPalindrome("racecar")); // true
console.log(isPalindrome("hello")); // false
console.log(isPalindrome("A man a plan a canal Panama")); // true
Count Character Occurrences
function charCount(str) {
const map = {};
for (let char of str) {
map[char] = (map[char] || 0) + 1;
}
return map;
}
console.log(charCount("javascript"));
// { j:1, a:3, v:1, s:1, c:1, r:1, i:1, p:1, t:1 }
Find the First Non-Repeating Character
function firstUniqueChar(str) {
const map = {};
for (let char of str) {
map[char] = (map[char] || 0) + 1;
}
for (let i = 0; i < str.length; i++) {
if (map[str[i]] === 1) return str[i];
}
return null;
}
console.log(firstUniqueChar("javascript")); // "j"
console.log(firstUniqueChar("aabb")); // null
Truncate a String to N Characters
function truncate(str, maxLength) {
if (str.length <= maxLength) return str;
return str.slice(0, maxLength) + '...';
}
console.log(truncate("Hello, Nawazish!", 8)); // "Hello, N..."
Why Understanding Built-in Behavior Matters
Here is the honest truth: in a real job, you will almost never need to rewrite trim() or includes(). JavaScript gives you perfectly good versions. Use them.
But understanding how they work changes how you think about problems. When you know that includes() is just a sliding window search, you start recognising that pattern in other problems. When you know that trim() is two pointers moving inward, you start seeing how to apply that idea in different contexts.
Every built-in method encodes a small algorithm. Learning to write them from scratch is learning to think like the people who designed the language.
That is the real value of string polyfills — not the output, but the thinking that goes into building them.
Key Takeaways
String methods live on
String.prototypeand return new strings — strings are immutableA polyfill replicates built-in behavior, either for compatibility or to understand it deeply
Most string operations are loops walking through characters — sliding windows, two pointers, accumulators
Know how to implement
trim,includes,repeat,startsWith, andpadStartfrom scratchCommon interview problems: reverse a string, palindrome check, char frequency, first unique character
The goal is not to avoid built-ins — it is to understand them well enough that you could build them yourself
The next time you type .trim() or .includes(), you will know exactly what JavaScript is doing behind the scenes. And when an interviewer asks you to implement it without the built-in, you will not hesitate.
If this helped, drop a reaction. I am writing through the full JavaScript fundamentals series publicly at nawazish.hashnode.dev — follow along if you are on the same path.
