functions.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Utilities for creating functions. Loosely inspired by the
  16. * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8.
  17. *
  18. * @author nicksantos@google.com (Nick Santos)
  19. */
  20. goog.provide('goog.functions');
  21. /**
  22. * Creates a function that always returns the same value.
  23. * @param {T} retValue The value to return.
  24. * @return {function():T} The new function.
  25. * @template T
  26. */
  27. goog.functions.constant = function(retValue) {
  28. return function() { return retValue; };
  29. };
  30. /**
  31. * Always returns false.
  32. * @type {function(...): boolean}
  33. */
  34. goog.functions.FALSE = goog.functions.constant(false);
  35. /**
  36. * Always returns true.
  37. * @type {function(...): boolean}
  38. */
  39. goog.functions.TRUE = goog.functions.constant(true);
  40. /**
  41. * Always returns NULL.
  42. * @type {function(...): null}
  43. */
  44. goog.functions.NULL = goog.functions.constant(null);
  45. /**
  46. * A simple function that returns the first argument of whatever is passed
  47. * into it.
  48. * @param {T=} opt_returnValue The single value that will be returned.
  49. * @param {...*} var_args Optional trailing arguments. These are ignored.
  50. * @return {T} The first argument passed in, or undefined if nothing was passed.
  51. * @template T
  52. */
  53. goog.functions.identity = function(opt_returnValue, var_args) {
  54. return opt_returnValue;
  55. };
  56. /**
  57. * Creates a function that always throws an error with the given message.
  58. * @param {string} message The error message.
  59. * @return {!Function} The error-throwing function.
  60. */
  61. goog.functions.error = function(message) {
  62. return function() { throw Error(message); };
  63. };
  64. /**
  65. * Creates a function that throws the given object.
  66. * @param {*} err An object to be thrown.
  67. * @return {!Function} The error-throwing function.
  68. */
  69. goog.functions.fail = function(err) {
  70. return function() { throw err; };
  71. };
  72. /**
  73. * Given a function, create a function that keeps opt_numArgs arguments and
  74. * silently discards all additional arguments.
  75. * @param {Function} f The original function.
  76. * @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0.
  77. * @return {!Function} A version of f that only keeps the first opt_numArgs
  78. * arguments.
  79. */
  80. goog.functions.lock = function(f, opt_numArgs) {
  81. opt_numArgs = opt_numArgs || 0;
  82. return function() {
  83. return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs));
  84. };
  85. };
  86. /**
  87. * Creates a function that returns its nth argument.
  88. * @param {number} n The position of the return argument.
  89. * @return {!Function} A new function.
  90. */
  91. goog.functions.nth = function(n) {
  92. return function() { return arguments[n]; };
  93. };
  94. /**
  95. * Like goog.partial(), except that arguments are added after arguments to the
  96. * returned function.
  97. *
  98. * Usage:
  99. * function f(arg1, arg2, arg3, arg4) { ... }
  100. * var g = goog.functions.partialRight(f, arg3, arg4);
  101. * g(arg1, arg2);
  102. *
  103. * @param {!Function} fn A function to partially apply.
  104. * @param {...*} var_args Additional arguments that are partially applied to fn
  105. * at the end.
  106. * @return {!Function} A partially-applied form of the function goog.partial()
  107. * was invoked as a method of.
  108. */
  109. goog.functions.partialRight = function(fn, var_args) {
  110. var rightArgs = Array.prototype.slice.call(arguments, 1);
  111. return function() {
  112. var newArgs = Array.prototype.slice.call(arguments);
  113. newArgs.push.apply(newArgs, rightArgs);
  114. return fn.apply(this, newArgs);
  115. };
  116. };
  117. /**
  118. * Given a function, create a new function that swallows its return value
  119. * and replaces it with a new one.
  120. * @param {Function} f A function.
  121. * @param {T} retValue A new return value.
  122. * @return {function(...?):T} A new function.
  123. * @template T
  124. */
  125. goog.functions.withReturnValue = function(f, retValue) {
  126. return goog.functions.sequence(f, goog.functions.constant(retValue));
  127. };
  128. /**
  129. * Creates a function that returns whether its argument equals the given value.
  130. *
  131. * Example:
  132. * var key = goog.object.findKey(obj, goog.functions.equalTo('needle'));
  133. *
  134. * @param {*} value The value to compare to.
  135. * @param {boolean=} opt_useLooseComparison Whether to use a loose (==)
  136. * comparison rather than a strict (===) one. Defaults to false.
  137. * @return {function(*):boolean} The new function.
  138. */
  139. goog.functions.equalTo = function(value, opt_useLooseComparison) {
  140. return function(other) {
  141. return opt_useLooseComparison ? (value == other) : (value === other);
  142. };
  143. };
  144. /**
  145. * Creates the composition of the functions passed in.
  146. * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).
  147. * @param {function(...?):T} fn The final function.
  148. * @param {...Function} var_args A list of functions.
  149. * @return {function(...?):T} The composition of all inputs.
  150. * @template T
  151. */
  152. goog.functions.compose = function(fn, var_args) {
  153. var functions = arguments;
  154. var length = functions.length;
  155. return function() {
  156. var result;
  157. if (length) {
  158. result = functions[length - 1].apply(this, arguments);
  159. }
  160. for (var i = length - 2; i >= 0; i--) {
  161. result = functions[i].call(this, result);
  162. }
  163. return result;
  164. };
  165. };
  166. /**
  167. * Creates a function that calls the functions passed in in sequence, and
  168. * returns the value of the last function. For example,
  169. * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).
  170. * @param {...Function} var_args A list of functions.
  171. * @return {!Function} A function that calls all inputs in sequence.
  172. */
  173. goog.functions.sequence = function(var_args) {
  174. var functions = arguments;
  175. var length = functions.length;
  176. return function() {
  177. var result;
  178. for (var i = 0; i < length; i++) {
  179. result = functions[i].apply(this, arguments);
  180. }
  181. return result;
  182. };
  183. };
  184. /**
  185. * Creates a function that returns true if each of its components evaluates
  186. * to true. The components are evaluated in order, and the evaluation will be
  187. * short-circuited as soon as a function returns false.
  188. * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).
  189. * @param {...Function} var_args A list of functions.
  190. * @return {function(...?):boolean} A function that ANDs its component
  191. * functions.
  192. */
  193. goog.functions.and = function(var_args) {
  194. var functions = arguments;
  195. var length = functions.length;
  196. return function() {
  197. for (var i = 0; i < length; i++) {
  198. if (!functions[i].apply(this, arguments)) {
  199. return false;
  200. }
  201. }
  202. return true;
  203. };
  204. };
  205. /**
  206. * Creates a function that returns true if any of its components evaluates
  207. * to true. The components are evaluated in order, and the evaluation will be
  208. * short-circuited as soon as a function returns true.
  209. * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).
  210. * @param {...Function} var_args A list of functions.
  211. * @return {function(...?):boolean} A function that ORs its component
  212. * functions.
  213. */
  214. goog.functions.or = function(var_args) {
  215. var functions = arguments;
  216. var length = functions.length;
  217. return function() {
  218. for (var i = 0; i < length; i++) {
  219. if (functions[i].apply(this, arguments)) {
  220. return true;
  221. }
  222. }
  223. return false;
  224. };
  225. };
  226. /**
  227. * Creates a function that returns the Boolean opposite of a provided function.
  228. * For example, (goog.functions.not(f))(x) is equivalent to !f(x).
  229. * @param {!Function} f The original function.
  230. * @return {function(...?):boolean} A function that delegates to f and returns
  231. * opposite.
  232. */
  233. goog.functions.not = function(f) {
  234. return function() { return !f.apply(this, arguments); };
  235. };
  236. /**
  237. * Generic factory function to construct an object given the constructor
  238. * and the arguments. Intended to be bound to create object factories.
  239. *
  240. * Example:
  241. *
  242. * var factory = goog.partial(goog.functions.create, Class);
  243. *
  244. * @param {function(new:T, ...)} constructor The constructor for the Object.
  245. * @param {...*} var_args The arguments to be passed to the constructor.
  246. * @return {T} A new instance of the class given in {@code constructor}.
  247. * @template T
  248. */
  249. goog.functions.create = function(constructor, var_args) {
  250. /**
  251. * @constructor
  252. * @final
  253. */
  254. var temp = function() {};
  255. temp.prototype = constructor.prototype;
  256. // obj will have constructor's prototype in its chain and
  257. // 'obj instanceof constructor' will be true.
  258. var obj = new temp();
  259. // obj is initialized by constructor.
  260. // arguments is only array-like so lacks shift(), but can be used with
  261. // the Array prototype function.
  262. constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
  263. return obj;
  264. };
  265. /**
  266. * @define {boolean} Whether the return value cache should be used.
  267. * This should only be used to disable caches when testing.
  268. */
  269. goog.define('goog.functions.CACHE_RETURN_VALUE', true);
  270. /**
  271. * Gives a wrapper function that caches the return value of a parameterless
  272. * function when first called.
  273. *
  274. * When called for the first time, the given function is called and its
  275. * return value is cached (thus this is only appropriate for idempotent
  276. * functions). Subsequent calls will return the cached return value. This
  277. * allows the evaluation of expensive functions to be delayed until first used.
  278. *
  279. * To cache the return values of functions with parameters, see goog.memoize.
  280. *
  281. * @param {function():T} fn A function to lazily evaluate.
  282. * @return {function():T} A wrapped version the function.
  283. * @template T
  284. */
  285. goog.functions.cacheReturnValue = function(fn) {
  286. var called = false;
  287. var value;
  288. return function() {
  289. if (!goog.functions.CACHE_RETURN_VALUE) {
  290. return fn();
  291. }
  292. if (!called) {
  293. value = fn();
  294. called = true;
  295. }
  296. return value;
  297. };
  298. };
  299. /**
  300. * Wraps a function to allow it to be called, at most, once. All
  301. * additional calls are no-ops.
  302. *
  303. * This is particularly useful for initialization functions
  304. * that should be called, at most, once.
  305. *
  306. * @param {function():*} f Function to call.
  307. * @return {function():undefined} Wrapped function.
  308. */
  309. goog.functions.once = function(f) {
  310. // Keep a reference to the function that we null out when we're done with
  311. // it -- that way, the function can be GC'd when we're done with it.
  312. var inner = f;
  313. return function() {
  314. if (inner) {
  315. var tmp = inner;
  316. inner = null;
  317. tmp();
  318. }
  319. };
  320. };
  321. /**
  322. * Wraps a function to allow it to be called, at most, once per interval
  323. * (specified in milliseconds). If the wrapper function is called N times within
  324. * that interval, only the Nth call will go through.
  325. *
  326. * This is particularly useful for batching up repeated actions where the
  327. * last action should win. This can be used, for example, for refreshing an
  328. * autocomplete pop-up every so often rather than updating with every keystroke,
  329. * since the final text typed by the user is the one that should produce the
  330. * final autocomplete results. For more stateful debouncing with support for
  331. * pausing, resuming, and canceling debounced actions, use {@code
  332. * goog.async.Debouncer}.
  333. *
  334. * @param {function(this:SCOPE, ...?)} f Function to call.
  335. * @param {number} interval Interval over which to debounce. The function will
  336. * only be called after the full interval has elapsed since the last call.
  337. * @param {SCOPE=} opt_scope Object in whose scope to call the function.
  338. * @return {function(...?): undefined} Wrapped function.
  339. * @template SCOPE
  340. */
  341. goog.functions.debounce = function(f, interval, opt_scope) {
  342. var timeout = 0;
  343. return /** @type {function(...?)} */ (function(var_args) {
  344. goog.global.clearTimeout(timeout);
  345. var args = arguments;
  346. timeout = goog.global.setTimeout(function() {
  347. f.apply(opt_scope, args);
  348. }, interval);
  349. });
  350. };
  351. /**
  352. * Wraps a function to allow it to be called, at most, once per interval
  353. * (specified in milliseconds). If the wrapper function is called N times in
  354. * that interval, both the 1st and the Nth calls will go through.
  355. *
  356. * This is particularly useful for limiting repeated user requests where the
  357. * the last action should win, but you also don't want to wait until the end of
  358. * the interval before sending a request out, as it leads to a perception of
  359. * slowness for the user.
  360. *
  361. * @param {function(this:SCOPE, ...?)} f Function to call.
  362. * @param {number} interval Interval over which to throttle. The function can
  363. * only be called once per interval.
  364. * @param {SCOPE=} opt_scope Object in whose scope to call the function.
  365. * @return {function(...?): undefined} Wrapped function.
  366. * @template SCOPE
  367. */
  368. goog.functions.throttle = function(f, interval, opt_scope) {
  369. var timeout = 0;
  370. var shouldFire = false;
  371. var args = [];
  372. var handleTimeout = function() {
  373. timeout = 0;
  374. if (shouldFire) {
  375. shouldFire = false;
  376. fire();
  377. }
  378. };
  379. var fire = function() {
  380. timeout = goog.global.setTimeout(handleTimeout, interval);
  381. f.apply(opt_scope, args);
  382. };
  383. return /** @type {function(...?)} */ (function(var_args) {
  384. args = arguments;
  385. if (!timeout) {
  386. fire();
  387. } else {
  388. shouldFire = true;
  389. }
  390. });
  391. };
  392. /**
  393. * Wraps a function to allow it to be called, at most, once per interval
  394. * (specified in milliseconds). If the wrapper function is called N times within
  395. * that interval, only the 1st call will go through.
  396. *
  397. * This is particularly useful for limiting repeated user requests where the
  398. * first request is guaranteed to have all the data required to perform the
  399. * final action, so there's no need to wait until the end of the interval before
  400. * sending the request out.
  401. *
  402. * @param {function(this:SCOPE, ...?)} f Function to call.
  403. * @param {number} interval Interval over which to rate-limit. The function will
  404. * only be called once per interval, and ignored for the remainer of the
  405. * interval.
  406. * @param {SCOPE=} opt_scope Object in whose scope to call the function.
  407. * @return {function(...?): undefined} Wrapped function.
  408. * @template SCOPE
  409. */
  410. goog.functions.rateLimit = function(f, interval, opt_scope) {
  411. var timeout = 0;
  412. var handleTimeout = function() {
  413. timeout = 0;
  414. };
  415. return /** @type {function(...?)} */ (function(var_args) {
  416. if (!timeout) {
  417. timeout = goog.global.setTimeout(handleTimeout, interval);
  418. f.apply(opt_scope, arguments);
  419. }
  420. });
  421. };