String Methods & Polyfills in Js

Introduction
Strings are one of the most commonly used data types in JavaScript, and working with them efficiently is a key skill for any developer. JavaScript provides many built-in string methods such as slice, substring, includes, and split that simplify string manipulation. However, understanding how these methods work internally is just as important as using them. This is where polyfills come in. Polyfills help us recreate built-in functionality manually, which deepens our understanding and prepares us for technical interviews. In this blog, we will explore string methods, why polyfills are important, and how to implement them step by step.
What String Methods Are
String methods are built-in functions provided by JavaScript to perform operations on strings. These methods allow developers to manipulate, search, and transform string data efficiently without writing complex logic from scratch.
Some commonly used string methods include:
slice()β extracts part of a stringtoUpperCase()β converts to uppercaseincludes()β checks if substring existssplit()β converts string into an array
Example
const str = "hello world";
console.log(str.slice(0, 5)); // "hello"
console.log(str.includes("world")); // true
console.log(str.toUpperCase()); // "HELLO WORLD"
These methods are optimized and easy to use, but they hide the underlying logic. Understanding that logic is important for building strong problem-solving skills.
Why Developers Write Polyfills
A polyfill is a custom implementation of a built-in method. Developers write polyfills to understand how JavaScript functions work internally or to provide support for older browsers that may not support certain features.
Polyfills are especially important for interviews because they test your ability to think logically and implement features from scratch instead of relying on built-in functions.
For example, instead of using includes(), you may be asked to implement it manually.
Implementing Simple String Utilities (Polyfills)
Letβs implement a few common string methods manually to understand their logic.
πΉ 1. Polyfill for includes()
function myIncludes(str, search) {
for (let i = 0; i <= str.length - search.length; i++) {
let match = true;
for (let j = 0; j < search.length; j++) {
if (str[i + j] !== search[j]) {
match = false;
break;
}
}
if (match) return true;
}
return false;
}
console.log(myIncludes("hello world", "world")); // true
π Logic: Compare characters one by one and check for match.
πΉ 2. Polyfill for slice()
function mySlice(str, start, end) {
let result = "";
for (let i = start; i < end; i++) {
result += str[i];
}
return result;
}
console.log(mySlice("hello", 1, 4)); // "ell"
π Logic: Loop from start to end and build new string.
πΉ 3. Polyfill for split()
function mySplit(str, separator) {
let result = [];
let current = "";
for (let char of str) {
if (char === separator) {
result.push(current);
current = "";
} else {
current += char;
}
}
result.push(current);
return result;
}
console.log(mySplit("a,b,c", ",")); // ["a","b","c"]
π Logic: Break string whenever separator is found.
Common Interview String Problems
String-based questions are very common in interviews because they test your understanding of loops, conditions, and logic building.
Some frequently asked problems include:
Reverse a string
Check for palindrome
Find frequency of characters
Remove duplicates from string
Check if one string is substring of another
Example: Reverse a String
function reverseString(str) {
let result = "";
for (let i = str.length - 1; i >= 0; i--) {
result += str[i];
}
return result;
}
console.log(reverseString("hello")); // "olleh"
Example: Palindrome Check
function isPalindrome(str) {
let reversed = str.split("").reverse().join("");
return str === reversed;
}
console.log(isPalindrome("madam")); // true
Importance of Understanding Built-in Behavior
Using built-in methods is easy, but understanding how they work internally is what makes you a strong developer. When you know the logic behind these methods:
You can solve problems without relying on shortcuts
You perform better in interviews
You write optimized and cleaner code
You understand edge cases (like empty strings, special characters)
For example, includes() internally compares characters sequentially, while split() builds arrays dynamically. Knowing this helps you debug and optimize your solutions.
String Processing Flow (Concept)
String operations generally follow a simple flow:
Input String β Process (loop/logic) β Output Result
Example:
"hello" β reverse logic β "olleh"
Polyfill Behavior Representation
Polyfills follow this pattern:
Built-in Method β Understand Logic β Recreate with Loops & Conditions
Example:
includes() β compare characters β return true/false
Conclusion
String methods are powerful tools in JavaScript, but true understanding comes from knowing how they work internally. Polyfills help bridge that gap by allowing developers to implement these methods from scratch. This not only improves problem-solving skills but also prepares you for technical interviews where such questions are common. By practicing string utilities and understanding their logic, you build a strong foundation in JavaScript that goes beyond just using built-in functions.
Important JavaScript Polyfills
Array.prototype.map Polyfill
The map method is used to transform each element of an array and return a new array. It does not modify the original array but instead applies a callback function to every element and stores the result.
A polyfill for map works by iterating through the array, applying the callback function to each element, and pushing the result into a new array.
Array.prototype.myMap = function (cb) {
let result = [];
for (let i = 0; i < this.length; i++) {
result.push(cb(this[i], i, this));
}
return result;
};
This implementation shows that map is essentially a loop combined with transformation logic.
Array.prototype.filter Polyfill
The filter method is used to return elements that satisfy a specific condition. It checks each element using a callback function and includes only those elements that return true.
The polyfill works by looping through the array and conditionally pushing elements into a new array.
Array.prototype.myFilter = function (cb) {
let result = [];
for (let i = 0; i < this.length; i++) {
if (cb(this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};
This demonstrates how filtering is just conditional selection during iteration.
Array.prototype.reduce Polyfill
The reduce method is used to convert an array into a single value. It accumulates results by applying a callback function to each element.
The polyfill initializes an accumulator and updates it on each iteration.
Array.prototype.myReduce = function (cb, initialValue) {
let acc = initialValue !== undefined ? initialValue : this[0];
let startIndex = initialValue !== undefined ? 0 : 1;
for (let i = startIndex; i < this.length; i++) {
acc = cb(acc, this[i], i, this);
}
return acc;
};
This shows that reduce is simply controlled accumulation over a loop.
Array.prototype.forEach Polyfill
The forEach method executes a function for each element in an array. Unlike map, it does not return a new array and is mainly used for side effects such as logging or updating values.
The polyfill is straightforward and involves iterating through the array and executing the callback.
Array.prototype.myForEach = function (cb) {
for (let i = 0; i < this.length; i++) {
cb(this[i], i, this);
}
};
This highlights that forEach is just iteration without returning anything.
Function.prototype.bind Polyfill
The bind method is used to create a new function with a fixed this context. It is commonly used when working with objects and callbacks.
The polyfill works by storing the original function and returning a new function that calls it with the desired context.
Function.prototype.myBind = function (context, ...args) {
const fn = this;
return function (...newArgs) {
return fn.apply(context, [...args, ...newArgs]);
};
};
This demonstrates how bind internally uses apply to control execution context.
Promise.all Polyfill
The Promise.all method takes an array of promises and resolves when all of them are resolved. If any promise fails, it rejects immediately.
The polyfill keeps track of resolved promises and stores results in order.
function myPromiseAll(promises) {
return new Promise((resolve, reject) => {
let result = [];
let completed = 0;
promises.forEach((p, i) => {
Promise.resolve(p)
.then(res => {
result[i] = res;
completed++;
if (completed === promises.length) {
resolve(result);
}
})
.catch(reject);
});
});
}
This shows how asynchronous coordination is handled internally.
String.prototype.includes Polyfill
The includes method checks whether a string contains a specific substring. Internally, it compares characters sequentially.
The polyfill uses nested loops to check for matches.
String.prototype.myIncludes = function (search) {
for (let i = 0; i <= this.length - search.length; i++) {
let match = true;
for (let j = 0; j < search.length; j++) {
if (this[i + j] !== search[j]) {
match = false;
break;
}
}
if (match) return true;
}
return false;
};
This highlights how substring search works at a low level.