Implement Array.prototype.filter
Reimplement filter as `myFilter` — easy until you remember the two things the spec cares about that a naive loop misses: sparse-array holes and the full `(value, index, array)` callback signature plus `thisArg`.
The problem
Add `Array.prototype.myFilter(callbackFn, thisArg)` that returns a new array of the elements for which `callbackFn` returns truthy. Naming it `myFilter` keeps the real `filter` intact for the autograder.
Two spec details do the real work here. Holes in a sparse array like `[1, , 3]` must be skipped entirely, not passed to the callback. And the callback receives `(value, index, array)`, with an optional `thisArg` that sets `this` inside it.
The approach
Use a classic indexed `for` loop, not `for...of`. That choice is the crux: `for...of` walks holes and hands you `undefined` for them, which is exactly what the spec says *not* to do. A counting loop lets me test each index explicitly instead.
Guard every index with `i in this` — that's the idiomatic hole check, true only for indices that actually exist, so gaps are skipped. For the survivors I call `callbackFn.call(thisArg, this[i], i, this)`, which both binds `thisArg` and passes the full `(value, index, array)` triple the spec promises. Truthy results get pushed onto the result array.
The solution
/**
* @template T
* @param {(value: T, index: number, array: Array<T>) => boolean} callbackFn
* @param {unknown} [thisArg]
* @returns {Array<T>}
*/
Array.prototype.myFilter = function (callbackFn, thisArg) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (i in this && callbackFn.call(thisArg, this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};Time O(n)Space O(n)