官术网_书友最值得收藏!

A higher-order solution

If we don't want to modify the original function, we'll create a higher-order function, which we'll, inspiredly, name once(). This function will receive a function as a parameter and will return a new function, which will work only a single time. (We'll be seeing more of higher-order functions in Chapter 6, Producing Functions - Higher-Order Functions; in particular, see section Doing things once, revisited.)

Underscore and LoDash already has a similar function, invoked as _.once(). Ramda also provides R.once(), and most FP libraries include similar functionality, so you wouldn't have to program it on your own.

Our once() function way seems imposing at first, but as you get accustomed to working in FP fashion, you'll get used to this sort of code, and will find it to be quite understandable:

const once = fn => {
let done = false;
return (...args) => {
if (!done) {
done = true;
fn(...args);
}
};
};

Let's go over some of the finer points of this function:

  • The first line shows that once() receives a function (fn()) as its parameter.
  • We are defining an internal, private done variable, by taking advantage of a closure, as in Solution #7, previously. We opted not to call it clicked, as previously, because you don't necessarily need to click on a button to call the function; we went for a more general term.
  • The line return (...args) => ... says that once() will return a function, with some (0, 1, or more) parameters. Note that we are using the spread syntax we saw in Chapter 1, Becoming Functional - Several Questions. With older versions of JS you'd have to work with the arguments object; see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/arguments for more on that. The ES8 way is simpler and shorter!
  • We assign done = true before calling fn(), just in case that function throws an exception. Of course, if you don't want to disable the function unless it has successfully ended, then you could move the assignment just below the fn() call.
  • After the setting is done, we finally call the original function. Note the use of the spread operator to pass along whatever parameters the original fn() had.

So, how would we use it? We don't even need to store the newly generated function in any place; we can simply write the onclick method, as shown as follows:

<button id="billButton" onclick="once(billTheUser)(some, sales, data)">
Bill me
</button>;

Pay close attention to the syntax! When the user clicks on the button, the function that gets called with the (some, sales, data) argument isn't billTheUser(), but rather the result of having called once() with billTheUser as a parameter. That result is the one that can be called only a single time.

Note that our once() function uses functions as first-class objects, arrow functions, closures, and the spread operator; back in Chapter 1, Becoming Functional - Several Questions, we said we'd be needing those, so we're keeping our word! All we are missing here from that chapter is recursion... but as the Rolling Stones sing, You Can't Always Get What You Want!

主站蜘蛛池模板: 永善县| 浦东新区| 江华| 稻城县| 醴陵市| 濉溪县| 凤冈县| 建瓯市| 宝鸡市| 喀喇沁旗| 泾阳县| 清苑县| 修武县| 中宁县| 平邑县| 且末县| 郧西县| 大理市| 桦川县| 丁青县| 柘荣县| 福建省| 喀什市| 赤城县| 枞阳县| 大庆市| 安庆市| 泰顺县| 新安县| 叙永县| 义马市| 高密市| 马鞍山市| 阜康市| 廉江市| 宜昌市| 西乌珠穆沁旗| 永和县| 双江| 夹江县| 五莲县|