# String Polyfills in JavaScript

## What are string methods?

In JavaScript, strings come with a powerful set of built-in methods functions attached to every string value that let you search, transform, slice, and inspect text. When you call `"hello".toUpperCase()`, you're using a method that JavaScript's engine provides automatically. These aren't magic; they're functions defined on `String.prototype`, the shared blueprint that every string inherits from.

The key insight for interview preparation is this: knowing what a method does isn't enough. Interviewers want to know how it works and whether you could rebuild it from scratch. That's where polyfills come in.

## Why developers write polyfills

A polyfill is a piece of code that implements a feature that the current runtime doesn't support or that you're implementing yourself to demonstrate understanding. When a new string method lands in the JavaScript specification, older browsers don't have it. Developers write polyfills to bridge that gap, attaching the implementation directly to `String.prototype` before the browser's built-in version would run.

But in interviews, polyfills serve a different purpose. They force you to reason about the logic behind familiar tools. Can you write `trim()` without calling `trim()`? Can you implement `includes()` using only index-based access? These questions reveal how deeply you understand strings as sequences of characters.

Here's how the string processing model works under the hood:

![](https://cdn.hashnode.com/uploads/covers/6950d1ca85602739c40abd67/f69eaa1a-2166-4df1-8ff5-2e5970c4abfe.png align="center")

One important detail the diagram highlights: strings in JavaScript are **immutable**. No string method ever modifies the original string.

## Implementing simple string utilities as polyfills

Before writing a polyfill, always check if the method already exists. This prevents overwriting the native implementation in environments that support it.

```javascript
if (!String.prototype.customTrim) {
  String.prototype.customTrim = function () {
    // `this` refers to the string value the method is called on
    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);
  };
}
```

The logic here is a two-pointer approach.

Advance from the left until you hit a non-space character, retreat from the right until you hit a non-space character, then slice out the middle. This is exactly the kind of thinking interviews test: can you express a simple operation in terms of indices and comparisons?

Here's how the polyfill checking behavior works visually:

![](https://cdn.hashnode.com/uploads/covers/6950d1ca85602739c40abd67/c056b850-f3a8-4ce9-8183-0d3b01a966be.png align="center")

## Common interview string methods to implement

### `includes(searchStr)`

The built-in method checks whether a substring exists anywhere in the string, returning `true` or `false`. The polyfill uses a sliding window: at every position, compare the next `searchStr.length` characters against the target.

```javascript
String.prototype.myIncludes = function (searchStr) {
  const str = String(this);
  const search = String(searchStr);

  if (search.length === 0) return true;
  if (search.length > str.length) return false;

  for (let i = 0; i <= str.length - search.length; i++) {
    if (str.slice(i, i + search.length) === search) return true;
  }
  return false;
};
```

Note the edge cases: an empty search string always returns `true` (this matches the spec), and a search string longer than the source immediately returns `false`.

### `repeat(count)`

This builds a new string by concatenating the original `count` times.

```javascript
String.prototype.myRepeat = function (count) {
  const n = Math.floor(count);
  if (n < 0 || n === Infinity) throw new RangeError('Invalid count value');
  let result = '';
  for (let i = 0; i < n; i++) result += this;
  return result;
};
```

### `startsWith(prefix)` and `endsWith(suffix)`

These are slice comparisons at fixed positions:

```javascript
String.prototype.myStartsWith = function (prefix) {
  return this.slice(0, prefix.length) === prefix;
};

String.prototype.myEndsWith = function (suffix) {
  if (suffix.length === 0) return true;
  return this.slice(-suffix.length) === suffix;
};
```

### `padStart(targetLength, padStr)` and `padEnd()`

Padding methods fill the string until it reaches a desired length:

```javascript
String.prototype.myPadStart = function (targetLength, padStr = ' ') {
  const str = String(this);
  if (str.length >= targetLength) return str;
  const padNeeded = targetLength - str.length;
  let padding = '';
  while (padding.length < padNeeded) padding += padStr;
  return padding.slice(0, padNeeded) + str;
};
```
