An even better solution
In one of the previous solutions, we mentioned that it would be a good idea to do something every time after the first, and not silently ignoring the user's clicks. We'll write a new higher-order function, that takes a second parameter; a function to be called every time from the second call onward:
const onceAndAfter = (f, g) => {
let done = false;
return (...args) => {
if (!done) {
done = true;
f(...args);
} else {
g(...args);
}
};
};
We have ventured further in higher-order functions; onceAndAfter takes two functions as parameters and produces a third one, which includes the other two within.
You could make onceAndAfter more powerful, by giving a default value for g, along the lines of const onceAndAfter = (f, g = ()=>{}) ... so if you didn't want to specify the second function, it would still work fine, because it would call a do nothing function, instead of causing an error.
We can do a quick-and-dirty test, along with the same lines as we did earlier:
const squeak = (x) => console.log(x, "squeak!!");
const creak = (x) => console.log(x, "creak!!");
const makeSound = onceAndAfter(squeak, creak);
makeSound("door"); // "door squeak!!"
makeSound("door"); // "door creak!!"
makeSound("door"); // "door creak!!"
makeSound("door"); // "door creak!!"
Writing a test for this new function isn't hard, only a bit longer:
describe("onceAndAfter", () => {
it("should call the first function once, and the other after", () => {
func1 = () => {};
spyOn(window, "func1");
func2 = () => {};
spyOn(window, "func2");
onceFn = onceAndAfter(func1, func2);
onceFn();
expect(func1).toHaveBeenCalledTimes(1);
expect(func2).toHaveBeenCalledTimes(0);
onceFn();
expect(func1).toHaveBeenCalledTimes(1);
expect(func2).toHaveBeenCalledTimes(1);
onceFn();
expect(func1).toHaveBeenCalledTimes(1);
expect(func2).toHaveBeenCalledTimes(2);
onceFn();
expect(func1).toHaveBeenCalledTimes(1);
expect(func2).toHaveBeenCalledTimes(3);
});
});
Notice that we always check that func1 is called only once. Similarly, we check func2; the count of calls starts at zero (the time that func1 is called), and from then on, it goes up by one on each call.