You have an array and you want a new array of the same length, where each slot is the result of running its original value through a function. That's Array.prototype.map — [1, 2, 3].map(x => x * 2) returns [2, 4, 6]. You'll implement it from scratch as Array.prototype.myMap so the global .map you rely on for testing stays untouched.
The work isn't the loop. The work is the awkward parts of the spec that the real map handles silently: sparse arrays, the thisArg argument, the three-parameter callback signature, and what happens when the callback adds new entries mid-iteration.
arr.myMap(callback, thisArg?)
// callback(currentValue, currentIndex, array) => mappedValue
// thisArg (optional): value to use as `this` when calling callback
// returns: a new array of the same length as `arr`
// Basic — transform each element.
[1, 2, 3].myMap((x) => x * 2);
// [2, 4, 6]
// Sparse array — holes stay holes; the callback is NOT called for hole indices.
const sparse = [1, , 3];
sparse.myMap((x) => x * 2);
// [2, <empty>, 6] // index 1 is still a hole, not undefined
// thisArg — bind `this` inside the callback.
const doubler = { factor: 2 };
[10, 20].myMap(function (x) {
return x * this.factor;
}, doubler);
// [20, 40]
[1, , 3] has a hole at index 1, not an undefined. Use i in this to detect holes; skip them. The hole must remain a hole in the output — assign to result[i] only when the callback runs, so absent indices stay absent.(currentValue, currentIndex, array). Predicates like (_, i) => i * 2 only work if you wire up the index.thisArg — when provided, the callback's this is bound to it. Use callback.call(thisArg, ...). When omitted, this inside a non-arrow callback is undefined in strict mode.this.length once before the loop. If the callback pushes new elements, you must NOT visit them.this. The input array stays untouched; the return value is a brand-new array.undefined is not a hole — if the callback returns undefined, the output gets undefined at that slot (a real, present undefined), distinct from a skipped hole.Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.