# 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 string
    
*   `toUpperCase()` → converts to uppercase
    
*   `includes()` → checks if substring exists
    
*   `split()` → converts string into an array
    

### Example

```plaintext
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()`

```plaintext
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()`

```plaintext
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()`

```plaintext
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

```plaintext
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

```plaintext
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:

```plaintext
Input String → Process (loop/logic) → Output Result
```

Example:

```plaintext
"hello" → reverse logic → "olleh"
```

* * *

## Polyfill Behavior Representation

Polyfills follow this pattern:

```plaintext
Built-in Method → Understand Logic → Recreate with Loops & Conditions
```

Example:

```plaintext
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](http://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.

```plaintext
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.

```plaintext
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.

```plaintext
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.

```plaintext
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.

```plaintext
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.

```plaintext
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.

```plaintext
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.

* * *
