Skip to the code
cf.

Array.prototype.some and every

Write Array.prototype.mySome(callback, thisArg) and Array.prototype.myEvery(callback, thisArg), which work like the built-in some and every without calling them. Both call callback(element, index, array) for the elements in order, with thisArg as its this.

mySome returns true as soon as the callback returns a truthy value, and false if it never does. myEvery returns false as soon as the callback returns a falsy value, and true if it never does. The callback isn't called for the elements after the one that settles the answer.

The result is always true or false, never the callback's own return value.

Holes (missing indexes, as in [1, , 3]) are skipped: the callback never sees them. So for an empty array, or one with only holes, mySome returns false and myEvery returns true, without calling the callback.

If callback isn't a function, throw a TypeError, even for an empty array.

[1, 5, 2].mySome((n) => n > 3);   // true: stops at 5
[1, 5, 2].myEvery((n) => n > 3);  // false: stops at 1
[0, "a"].mySome((x) => x);        // true, not "a"
[].mySome((n) => n > 3);          // false
[].myEvery((n) => n > 3);         // true
[, 4, , 6].myEvery((n) => n > 3); // true: holes are skipped

What the tests check

  1. mySome returns true when the callback accepts any element
    expect([1, 5, 2].mySome((n) => n > 3)).toBe(true);
    expect([1, 2, 3].mySome((n) => n > 3)).toBe(false);
    
  2. myEvery returns true only when the callback accepts every element
    expect([4, 5, 6].myEvery((n) => n > 3)).toBe(true);
    expect([4, 1, 6].myEvery((n) => n > 3)).toBe(false);
    
  3. returns true or false, not the callback's result
    expect([0, "a"].mySome((x) => x)).toBe(true);
    expect([0, ""].mySome((x) => x)).toBe(false);
    expect([1, "a"].myEvery((x) => x)).toBe(true);
    expect([1, null].myEvery((x) => x)).toBe(false);
    
  4. stops at the element that settles the answer
    const some = spy((n) => n > 3);
    expect([1, 5, 2, 7].mySome(some)).toBe(true);
    expect(some).toHaveBeenCalledTimes(2);
    const every = spy((n) => n > 3);
    expect([5, 1, 7, 2].myEvery(every)).toBe(false);
    expect(every).toHaveBeenCalledTimes(2);
    
  5. calls the callback with the element, its index, and the array, and thisArg as this
    const letters = ["a", "b"];
    const context = { name: "context" };
    const some = spy(() => false);
    letters.mySome(some, context);
    expect(some.calls.map((call) => call.args)).toEqual([["a", 0, letters], ["b", 1, letters]]);
    expect(some.calls[1].args[2]).toBe(letters);
    expect(some.calls[0].this).toBe(context);
    const every = spy(() => true);
    letters.myEvery(every, context);
    expect(every.calls.map((call) => call.args)).toEqual([["a", 0, letters], ["b", 1, letters]]);
    expect(every.calls[1].args[2]).toBe(letters);
    expect(every.calls[0].this).toBe(context);
    
  6. skips holes
    const some = spy((x) => x === undefined);
    expect([1, , 3].mySome(some)).toBe(false);
    expect(some).toHaveBeenCalledTimes(2);
    const every = spy((n) => n > 3);
    expect([, 4, , 6].myEvery(every)).toBe(true);
    expect(every).toHaveBeenCalledTimes(2);
    
  7. gives false for mySome and true for myEvery on an empty array, without calling back
    const accept = spy(() => true);
    expect([].mySome(accept)).toBe(false);
    expect([, ,].mySome(accept)).toBe(false);
    const reject = spy(() => false);
    expect([].myEvery(reject)).toBe(true);
    expect([, ,].myEvery(reject)).toBe(true);
    expect(accept).not.toHaveBeenCalled();
    expect(reject).not.toHaveBeenCalled();
    
  8. throws a TypeError when callback isn't a function, even for an empty array
    expect(() => [1, 2].mySome("big")).toThrow(TypeError);
    expect(() => [1, 2].myEvery(null)).toThrow(TypeError);
    expect(() => [].mySome()).toThrow(TypeError);
    expect(() => [].myEvery({})).toThrow(TypeError);
    
  9. works without the built-in some and every
    const builtIn = { some: Array.prototype.some, every: Array.prototype.every };
    Array.prototype.some = function () {
      throw new Error("mySome called the built-in some");
    };
    Array.prototype.every = function () {
      throw new Error("myEvery called the built-in every");
    };
    let results;
    try {
      results = [[1, 5].mySome((n) => n > 3), [1, 5].myEvery((n) => n > 3)];
    } finally {
      Array.prototype.some = builtIn.some;
      Array.prototype.every = builtIn.every;
    }
    expect(results).toEqual([true, false]);
    

Learn more

solution.jsSaved in this browser

Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.

Ctrl + Enter runs the tests (⌘ + Enter on a Mac).