Introduction: Why String Manipulation Still Matters
Imagine this: You’re in a high-stakes JavaScript interview. The interviewer leans in and says, “Implement trim(), replaceAll(), and split() from scratch — no built-ins allowed.” Your pulse quickens… but then you smile. Because you’ve already read my blog, so no worries at all!
String methods are like everyday-needs of JavaScript. They power form validation, data cleaning, URL parsing, and almost every dynamic UI you’ve ever built. Yet most developers treat them as magic.
In this complete guide, we’ll break them down completely: what string methods really are, why polyfills are essential, a full deep-dive into all 15 string polyfills I personally wrote (available in my Polyfills Library on GitHub), the most common interview problems, and — most importantly — the exact logic behind every built-in so you can think like the JavaScript engine itself.
Let’s turn “it just works” into “I know exactly how it works.”
What Are String Methods in JavaScript?
String methods are functions that are attached to String.prototype. When you call "ritam".toUpperCase(), JavaScript is secretly doing:
String.prototype.toUpperCase = function() { /* native optimized code */ };
Key concepts every developer should internalize:
- Strings in JavaScript are immutable — every method returns a new string.
- Most methods loop through characters (or use fast native shortcuts).
- They operate on
this(the current string instance). - Common categories: inspection (
includes,indexOf), transformation (trim,replace), extraction (slice,substring), and utility (repeat,padStart).
Understanding this flow is your foundation for writing perfect polyfills.
Why Developers Write Polyfills
Polyfills are pure gold for three reasons:
-
Backward compatibility — older browsers or restricted environments might not have
replaceAll,at(), etc. - Deep learning — writing a polyfill forces you to understand the exact algorithm the browser uses. It builds thought process of every developers.
- Interview dominance — interviewers specifically ask you to implement these from scratch to test real understanding.
Polyfills turn you from a user of JavaScript into an engineer who knows the language inside-out.
Implementing All String Utilities – My Complete Polyfill Library
Here are all 15 polyfills exactly as I wrote them, with detailed explanations of the logic, how they mimic built-in behavior, and why the implementation matters for interviews.
1. firstCap() – Capitalize first letter using ASCII math
String.prototype.firstCap = function() {
let charCode = this.charCodeAt(0);
if(charCode >= 97 && charCode <= 122) {
return String.fromCharCode(charCode - 32) + this.slice(1);
}
return this;
};
Logic & Interview Insight: Pure ASCII manipulation. Lowercase letters are 97-122; subtract 32 to get uppercase. No toUpperCase() used — shows you understand character encoding. The String.fromCharCode() static method returns a string created from the specified sequence of UTF-16 code units. Perfect for “capitalize without built-ins” questions.
2. lastCap() – Capitalize last letter
String.prototype.lastCap = function() {
let charCode = this.charCodeAt(this.length - 1);
if(charCode >= 97 && charCode <= 122) {
return this.slice(0, this.length - 1) + String.fromCharCode(charCode - 32);
}
return this;
};
Logic: Same ASCII trick but targets the final character. Teaches precise index handling.
3. padBetween() – Insert separator between every character
String.prototype.padBetween = function(pad) {
let result = "";
for(let i=0; i<this.length; i++) {
result = result + this[i] + (i<this.length-1 ? pad : "");
}
return result;
};
Logic: Builds a new string while adding the pad only between characters. Great interview question for “insert separator without split + join”.
4. reverse() – Classic reversal
String.prototype.reverse = function() {
let newString = "";
for(let i=this.length-1; i>=0; i--) {
newString = newString + this[i];
}
return newString;
};
Logic: Backward iteration + concatenation. Interviewers expect this exact pattern (or two-pointer in-place for arrays).
5. remove() – Remove all occurrences of a character
String.prototype.remove = function(removeThis) {
let newString = "";
for(let i=0; i<this.length; i++) {
if(this[i] !== removeThis) {
newString = newString + this[i];
}
}
return newString;
};
Logic: Skip matching characters while building new string. Direct O(n) solution.
6. replaceBy() – Custom replace
String.prototype.replaceBy = function(search, replace) {
let newString = "";
let searchLength = search.length;
for(let i=0; i<this.length; i++) {
if(this.slice(i, i+searchLength) === search) {
newString = newString + replace;
i = i + searchLength - 1;
} else {
newString = newString + this[i];
}
}
return newString;
};
Logic: Sliding window comparison using slice. Foundation for understanding replaceAll.
7. include() – Custom includes()
String.prototype.include = function(search) {
for(let i=0; i<this.length; i++) {
if(this.slice(i, i+search.length) === search) {
return true;
}
}
return false;
};
Logic: Exact substring matching loop. Early return on match.
8. concatinate() – Safe concatenation
String.prototype.concatinate = function(separator, newStr) {
return this + separator + newStr;
};
Logic: Simple but demonstrates chaining with other polyfills (see example in repo).
9. repeatString() – Custom repeat()
String.prototype.repeatString = function(count) {
let result = "";
for(let i=0; i<count; i++) {
result = result + this;
}
return result;
};
Logic: Loop-based repetition. Shows why repeat() is O(n × count).
10. subString() – Custom substring()
String.prototype.subString = function(start, end){
let result = "";
while(start < end && start < this.length) {
result = result + this[start];
start++;
}
return result;
};
Logic: Boundary-safe extraction with manual loop.
11. sliceUp() – Custom slice() with optional delete + insert
String.prototype.sliceUp = function(start, deleteCount, insertStr) {
let result = "";
for(let i=0; i<start; i++) {
result += this[i];
}
for(let i=0; i<insertStr.length; i++) {
result += insertStr[i];
}
for(let i=start+deleteCount; i<this.length; i++) {
result += this[i];
}
return result;
};
Logic: Three-phase build: prefix + insert + suffix. Extremely useful in interview “edit string at index” problems.
12. splitUp() – Full custom split()
String.prototype.splitUp = function(separator) {
let result = [];
if(separator === "")
return Array.from(this);
else{
if(!this.include(separator)) {
result.push(this);
} else {
let targetIndex = this.indexOf(separator);
let item = "";
for(let i=0; i<this.length; i++) {
if(i === targetIndex) {
result.push(item);
item = "";
targetIndex = this.indexOf(separator, targetIndex+1);
} else {
item += this[i];
}
}
result.push(item);
}
}
return result;
}
Logic: Handles empty separator + multiple occurrences using include() and index tracking.
13. joinUp() – Custom join() on Array.prototype
Array.prototype.joinUp = function(separator) {
if(this.length === 0) return this.toString();
let result = "";
for(let i=0; i<this.length; i++) {
result += (this[i] + (i<this.length-1 ? separator : ""));
}
return result;
};
Logic: Pairs perfectly with splitUp — the classic interview combo.
14. trimmer() – Custom trim()
String.prototype.trimmer = function() {
let start = 0, end = this.length-1;
while(this[start] === " ") start++;
while(this[end] === " ") end--;
return this.slice(start, end+1);
};
Logic: Two-pointer inward scan. Most elegant O(n) trim implementation.
15. toUpper() – Custom toUpperCase()
String.prototype.toUpper = function() {
let result = "";
for(let i=0; i<this.length; i++) {
let charCode = this.charCodeAt(i);
if(charCode >= 97 && charCode <= 122) {
result += String.fromCharCode(charCode - 32);
} else {
result += this[i];
}
}
return result;
};
Logic: Full ASCII conversion for every character. Complete understanding of case conversion.
Common Interview String Problems (Solved with These Polyfills)
- Reverse a string →
reverse() - Trim whitespace →
trimmer() - Replace all occurrences →
replaceBy()+ loop - Split and join custom →
splitUp()+joinUp() - Capitalize first/last →
firstCap()/lastCap() - Remove characters →
remove() - Check substring →
include() - Insert between chars →
padBetween()
Always mention time complexity (usually O(n)) and immutability in your explanation.
Importance of Understanding Built-in Behavior
When you’ve written these 15 polyfills, you no longer guess — you know. You debug faster, write more efficient code, and impress interviewers by explaining the exact algorithm the browser uses.
Conclusion: Level Up Your JavaScript Game Today
These polyfills aren’t just code — they’re a complete mindset shift. They transform you from someone who uses JavaScript into someone who masters it.
Start today: pick any one from the full GitHub library, understand every line, then try extending it. The next time an interviewer says “implement this without built-ins,” you’ll walk in confident.
You’ve got this.
Happy coding, and may your strings always be perfectly processed! 🚀
Star the repo if these helped you crush an interview. I’d love to hear which polyfill you used first!
~ Written by Ritam – turning complex JS concepts into crystal-clear understanding.

Top comments (0)