|
| 1 | +Functions are one of the fundamental building blocks in JavaScript. It is |
| 2 | +similar to a procedure—a set of statements that performs a task or calculates a |
| 3 | +value [(1)]. It can accept some **parameters**, and may define some **local** |
| 4 | +**variables** necessary for performing the desired *operation*. These |
| 5 | +*parameters* and *local variables* are contained in the **scope of the** |
| 6 | +**function**, and *cannot* be accessed from the *outside*. However, a function can |
| 7 | +access variables *external to itself* (as long as they are not *overridden*), |
| 8 | +such as *global variables* or *variables* in the scope this function is |
| 9 | +*encapsulated in*. A **nested function** can access *free variables* that |
| 10 | +are defined in *outer scopes*, even when it is being *invoked* **away** from |
| 11 | +where it is *defined*. It does this by **capturing** the *free variables* (by |
| 12 | +*reference*) into a **closure** [(1)]. *Closure*, *arrow functions*, and more, |
| 13 | +are *functional language features* based on [lambda calculus]. |
| 14 | + |
| 15 | +This package includes a number of methods to *transform functions*. This enables |
| 16 | +you to obtain a desired function by transforming the behavior of existing |
| 17 | +functions (*without actually executing them*). The **result** of a function can |
| 18 | +be manipulated with [negate]. In case a *pure* function is expensive, its |
| 19 | +results can **cached** with [memoize]. **Parameters** of a function can be |
| 20 | +manipulated with [reverse], [spread], [unspread]. [reverse] flips the order of |
| 21 | +parameters, [spread] spreads the first array parameter of a function, and |
| 22 | +[unspread] combines all parameters into the first parameter (array). If you want |
| 23 | +some **functional** **behavior**, [compose], [composeRight], [curry], and |
| 24 | +[curryRight] can be used. [composeRight] is also known as [pipe-forward |
| 25 | +operator] or [function chaining]. If you are unfamiliar, [Haskell] is a great |
| 26 | +purely functional language, and there is great [haskell beginner guide] to learn |
| 27 | +from. |
| 28 | + |
| 29 | +To control invocation **time** of a function, use [delay]. A function can be |
| 30 | +**rate controlled** with [restrict], [debounce], [debounceEarly], [throttle], |
| 31 | +[throttleEarly]. [debounce] and [debounceEarly] prevent the invocation of a |
| 32 | +function during **hot** periods (when there are too many calls), and can be used |
| 33 | +for example to issue AJAX request after user input has stopped (for certain |
| 34 | +delay time). [throttle] and [throttleEarly] can be used to limit the rate of |
| 35 | +invocation of a function, and can be used for example to minimize system usage |
| 36 | +when a user is [constantly refreshing a webpage]. Except [restrict], all |
| 37 | +*rate/time control* methods can be *flushed* (`flush()`) to invoke the target |
| 38 | +function immediately, or *cleared* (`clear()`) to disable invocation of the |
| 39 | +target function. |
| 40 | + |
| 41 | +In addition, [is], [isAsync], [isGenerator], [name], and [length] obtain |
| 42 | +metadata (about) information on a function. To attach a `this` to a function, |
| 43 | +use [bind]. A few generic functions are also included: [NOOP], [FALSE], [TRUE], |
| 44 | +[IDENTITY], [COMPARE], [ARGUMENTS]. |
| 45 | + |
| 46 | +▌ |
| 47 | +📦 [JSR](https://jsr.io/@nodef/extra-function), |
| 48 | +📰 [Docs](https://jsr.io/@nodef/extra-function/doc). |
| 49 | + |
| 50 | +[(1)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions |
| 51 | +[lambda calculus]: https://en.wikipedia.org/wiki/Lambda_calculus |
| 52 | +[pipe-forward operator]: https://stackoverflow.com/questions/1457140/haskell-composition-vs-fs-pipe-forward-operator |
| 53 | +[function chaining]: https://www.npmjs.com/package/chain-function |
| 54 | +[Haskell]: https://www.haskell.org |
| 55 | +[haskell beginner guide]: http://learnyouahaskell.com |
| 56 | +[constantly refreshing a webpage]: https://tenor.com/view/social-network-mark-zuckerberg-refresh-movie-jesse-eisenberg-gif-12095762 |
| 57 | + |
| 58 | +<br> |
| 59 | + |
| 60 | + |
| 61 | +```javascript |
| 62 | +import * as xfunction from "jsr:@nodef/extra-function"; |
| 63 | + |
| 64 | +const fn1 = xfunction.composeRight(x => x*x, x => x+2); |
| 65 | +fn1(10); |
| 66 | +// → 102 |
| 67 | + |
| 68 | +const fn2 = xfunction.curry((x, y) => x+y); |
| 69 | +fn2(2)(3); |
| 70 | +// → 7 |
| 71 | + |
| 72 | +const fn3 = xfunction.unspread(Math.max); |
| 73 | +fn3([2, 3, 1]); |
| 74 | +// → 1.25 |
| 75 | +``` |
| 76 | + |
| 77 | +<br> |
| 78 | +<br> |
| 79 | + |
| 80 | + |
| 81 | +## Index |
| 82 | + |
| 83 | +| Name | Description | |
| 84 | +| ---- | ---- | |
| 85 | +| [NOOP] | Do nothing. | |
| 86 | +| [FALSE] | Return false. | |
| 87 | +| [TRUE] | Return false. | |
| 88 | +| [IDENTITY] | Return the same (first) value. | |
| 89 | +| [COMPARE] | Compare two values. | |
| 90 | +| [ARGUMENTS] | Return the arguments passed as a array. | |
| 91 | +| | | |
| 92 | +| [name] | Get the name of a function. | |
| 93 | +| [length] | Get the number of parameters of a function. | |
| 94 | +| | | |
| 95 | +| [bind] | Bind this-object, and optional prefix arguments to a function. | |
| 96 | +| | | |
| 97 | +| [call] | Invoke a function with specified this-object, and arguments provided individually. | |
| 98 | +| [apply] | Invoke a function with specified this-object, and arguments provided as an array. | |
| 99 | +| | | |
| 100 | +| [is] | Check if value is a function. | |
| 101 | +| [isAsync] | Check if value is an async function. | |
| 102 | +| [isGenerator] | Check if value is a generator function. | |
| 103 | +| | | |
| 104 | +| [contextify] | Contextify a function by accepting the first parameter as this-object. | |
| 105 | +| [decontextify] | Decontextify a function by accepting this-object as the first argument. | |
| 106 | +| | | |
| 107 | +| [negate] | Generate a result-negated version of a function. | |
| 108 | +| | | |
| 109 | +| [memoize] | Generate result-cached version of a function. | |
| 110 | +| | | |
| 111 | +| [reverse] | Generate a parameter-reversed version of a function. | |
| 112 | +| [spread] | Generate a (first) parameter-spreaded version of a function. | |
| 113 | +| [unspread] | Generate a (first) parameter-collapsed version of a function. | |
| 114 | +| [attach] | Attach prefix arguments to leftmost parameters of a function. | |
| 115 | +| [attachRight] | Attach suffix arguments to rightmost parameters of a function. | |
| 116 | +| | | |
| 117 | +| [compose] | Compose functions together, in applicative order. | |
| 118 | +| [composeRight] | Compose functions together, such that result is piped forward. | |
| 119 | +| [curry] | Generate curried version of a function. | |
| 120 | +| [curryRight] | Generate right-curried version of a function. | |
| 121 | +| | | |
| 122 | +| [defer] | Generate deferred version of a function, that executes after the current stack has cleared. | |
| 123 | +| [delay] | Generate delayed version of a function. | |
| 124 | +| | | |
| 125 | +| [restrict] | Generate restricted-use version of a function. | |
| 126 | +| [restrictOnce] | Restrict a function to be used only once. | |
| 127 | +| [restrictBefore] | Restrict a function to be used only upto a certain number of calls. | |
| 128 | +| [restrictAfter] | Restrict a function to be used only after a certain number of calls. | |
| 129 | +| | | |
| 130 | +| [debounce] | Generate debounced version of a function. | |
| 131 | +| [debounceEarly] | Generate leading-edge debounced version of a function. | |
| 132 | +| [throttle] | Generate throttled version of a function. | |
| 133 | +| [throttleEarly] | Generate leading-edge throttled version of a function. | |
| 134 | + |
| 135 | +<br> |
| 136 | +<br> |
| 137 | + |
| 138 | + |
| 139 | +## References |
| 140 | + |
| 141 | +- [MDN Web docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference) |
| 142 | +- [Lodash documentation](https://lodash.com/docs/4.17.15) |
| 143 | +- [Underscore.js documentation](https://underscorejs.org/) |
| 144 | +- [Function composition](https://en.wikipedia.org/wiki/Function_composition) |
| 145 | +- [Debouncing and Throttling Explained Through Examples by David Corbacho](https://css-tricks.com/debouncing-throttling-explained-examples/) |
| 146 | +- [Learn You a Haskell for Great Good!: Higher order functions by Miran Lipovaca](http://learnyouahaskell.com/higher-order-functions) |
| 147 | +- [How to know if a function is async?](https://stackoverflow.com/questions/38508420/how-to-know-if-a-function-is-async) |
| 148 | +- [Check if function is a generator](https://stackoverflow.com/questions/16754956/check-if-function-is-a-generator) |
| 149 | +- [Haskell composition (.) vs F#'s pipe forward operator (|>)](https://stackoverflow.com/questions/1457140/haskell-composition-vs-fs-pipe-forward-operator) |
| 150 | +- [JavaScript Detect Async Function by David Walsh](https://davidwalsh.name/javascript-detect-async-function) |
| 151 | +- [is-function package by Stephen Sugden](https://www.npmjs.com/package/is-function) |
| 152 | +- [is-async-function package by Jordan Harband](https://www.npmjs.com/package/is-async-function) |
| 153 | +- [is-callback-function package by Charlike Mike Reagent](https://www.npmjs.com/package/is-callback-function) |
| 154 | +- [is-generator-fn package by Sindre Sorhus](https://www.npmjs.com/package/is-generator-fn) |
| 155 | +- [is-generator-function package by Jordan Harband](https://www.npmjs.com/package/is-generator-function) |
| 156 | +- [fn-name package by Sindre Sorhus](https://www.npmjs.com/package/fn-name) |
| 157 | +- [memoizee package by Mariusz Nowak](https://www.npmjs.com/package/memoizee) |
| 158 | +- [memoizerific package by @thinkloop](https://www.npmjs.com/package/memoizerific) |
| 159 | +- [compose-function package by Christoph Hermann](https://www.npmjs.com/package/compose-function) |
| 160 | +- [chain-function package by Jason Quense](https://www.npmjs.com/package/chain-function) |
| 161 | +- [@spudly/curry package by Stephen Sorensen](https://www.npmjs.com/package/@spudly/curry) |
| 162 | +- [one-time package by Arnout Kazemier](https://www.npmjs.com/package/one-time) |
| 163 | +- [onetime package by Sindre Sorhus](https://www.npmjs.com/package/onetime) |
| 164 | +- [once package by Isaac Z. Schlueter](https://www.npmjs.com/package/once) |
| 165 | +- [debounce package by @component](https://www.npmjs.com/package/debounce) |
| 166 | +- [throttle-debounce package by Ivan Nikolić](https://www.npmjs.com/package/throttle-debounce) |
| 167 | +- [throttleit package by @component](https://www.npmjs.com/package/throttleit) |
| 168 | + |
| 169 | +<br> |
| 170 | +<br> |
| 171 | + |
| 172 | + |
| 173 | +[](https://wolfram77.github.io)<br> |
| 174 | +[](https://nodef.github.io) |
| 175 | + |
| 176 | + |
| 177 | + |
| 178 | +[NOOP]: https://jsr.io/@nodef/extra-function/doc/~/NOOP |
| 179 | +[FALSE]: https://jsr.io/@nodef/extra-function/doc/~/FALSE |
| 180 | +[TRUE]: https://jsr.io/@nodef/extra-function/doc/~/TRUE |
| 181 | +[IDENTITY]: https://jsr.io/@nodef/extra-function/doc/~/IDENTITY |
| 182 | +[COMPARE]: https://jsr.io/@nodef/extra-function/doc/~/COMPARE |
| 183 | +[ARGUMENTS]: https://jsr.io/@nodef/extra-function/doc/~/ARGUMENTS |
| 184 | +[is]: https://jsr.io/@nodef/extra-function/doc/~/is |
| 185 | +[isAsync]: https://jsr.io/@nodef/extra-function/doc/~/isAsync |
| 186 | +[isGenerator]: https://jsr.io/@nodef/extra-function/doc/~/isGenerator |
| 187 | +[name]: https://jsr.io/@nodef/extra-function/doc/~/name |
| 188 | +[bind]: https://jsr.io/@nodef/extra-function/doc/~/bind |
| 189 | +[negate]: https://jsr.io/@nodef/extra-function/doc/~/negate |
| 190 | +[memoize]: https://jsr.io/@nodef/extra-function/doc/~/memoize |
| 191 | +[reverse]: https://jsr.io/@nodef/extra-function/doc/~/reverse |
| 192 | +[spread]: https://jsr.io/@nodef/extra-function/doc/~/spread |
| 193 | +[unspread]: https://jsr.io/@nodef/extra-function/doc/~/unspread |
| 194 | +[compose]: https://jsr.io/@nodef/extra-function/doc/~/compose |
| 195 | +[composeRight]: https://jsr.io/@nodef/extra-function/doc/~/composeRight |
| 196 | +[curry]: https://jsr.io/@nodef/extra-function/doc/~/curry |
| 197 | +[curryRight]: https://jsr.io/@nodef/extra-function/doc/~/curryRight |
| 198 | +[delay]: https://jsr.io/@nodef/extra-function/doc/~/delay |
| 199 | +[debounce]: https://jsr.io/@nodef/extra-function/doc/~/debounce |
| 200 | +[debounceEarly]: https://jsr.io/@nodef/extra-function/doc/~/debounceEarly |
| 201 | +[throttle]: https://jsr.io/@nodef/extra-function/doc/~/throttle |
| 202 | +[throttleEarly]: https://jsr.io/@nodef/extra-function/doc/~/throttleEarly |
| 203 | +[restrict]: https://jsr.io/@nodef/extra-function/doc/~/restrict |
| 204 | +[length]: https://jsr.io/@nodef/extra-function/doc/~/length |
| 205 | +[call]: https://jsr.io/@nodef/extra-function/doc/~/call |
| 206 | +[apply]: https://jsr.io/@nodef/extra-function/doc/~/apply |
| 207 | +[contextify]: https://jsr.io/@nodef/extra-function/doc/~/contextify |
| 208 | +[decontextify]: https://jsr.io/@nodef/extra-function/doc/~/decontextify |
| 209 | +[attach]: https://jsr.io/@nodef/extra-function/doc/~/attach |
| 210 | +[attachRight]: https://jsr.io/@nodef/extra-function/doc/~/attachRight |
| 211 | +[defer]: https://jsr.io/@nodef/extra-function/doc/~/defer |
| 212 | +[restrictOnce]: https://jsr.io/@nodef/extra-function/doc/~/restrictOnce |
| 213 | +[restrictBefore]: https://jsr.io/@nodef/extra-function/doc/~/restrictBefore |
| 214 | +[restrictAfter]: https://jsr.io/@nodef/extra-function/doc/~/restrictAfter |
0 commit comments