Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/functions/functions.js
4500 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Utilities for creating functions. Loosely inspired by these
9
* java classes from the Guava library:
10
* com.google.common.base.Functions
11
* https://google.github.io/guava/releases/snapshot-jre/api/docs/index.html?com/google/common/base/Functions.html
12
*
13
* com.google.common.base.Predicates
14
* https://google.github.io/guava/releases/snapshot-jre/api/docs/index.html?com/google/common/base/Predicates.html
15
*
16
* More about these can be found at
17
* https://github.com/google/guava/wiki/FunctionalExplained
18
*/
19
20
21
goog.provide('goog.functions');
22
23
24
/**
25
* Creates a function that always returns the same value.
26
* @param {T} retValue The value to return.
27
* @return {function():T} The new function.
28
* @template T
29
*/
30
goog.functions.constant = function(retValue) {
31
'use strict';
32
return function() {
33
'use strict';
34
return retValue;
35
};
36
};
37
38
39
/**
40
* Always returns false.
41
* @type {function(...): boolean}
42
*/
43
goog.functions.FALSE = function() {
44
'use strict';
45
return false;
46
};
47
48
49
/**
50
* Always returns true.
51
* @type {function(...): boolean}
52
*/
53
goog.functions.TRUE = function() {
54
'use strict';
55
return true;
56
};
57
58
59
/**
60
* Always returns `null`.
61
* @type {function(...): null}
62
*/
63
goog.functions.NULL = function() {
64
'use strict';
65
return null;
66
};
67
68
69
/**
70
* Always returns `undefined`.
71
* @type {function(...): undefined}
72
*/
73
goog.functions.UNDEFINED = function() {
74
return undefined;
75
};
76
77
/**
78
* Always returns `undefined` (loosely-typed version).
79
* @type {!Function}
80
*/
81
goog.functions.EMPTY = /** @type {?} */ (goog.functions.UNDEFINED);
82
83
84
/**
85
* A simple function that returns the first argument of whatever is passed
86
* into it.
87
* @param {T=} opt_returnValue The single value that will be returned.
88
* @param {...*} var_args Optional trailing arguments. These are ignored.
89
* @return {T} The first argument passed in, or undefined if nothing was passed.
90
* @template T
91
*/
92
goog.functions.identity = function(opt_returnValue, var_args) {
93
'use strict';
94
return opt_returnValue;
95
};
96
97
98
/**
99
* Creates a function that always throws an error with the given message.
100
* @param {string} message The error message.
101
* @return {!Function} The error-throwing function.
102
*/
103
goog.functions.error = function(message) {
104
'use strict';
105
return function() {
106
'use strict';
107
throw new Error(message);
108
};
109
};
110
111
112
/**
113
* Creates a function that throws the given object.
114
* @param {*} err An object to be thrown.
115
* @return {!Function} The error-throwing function.
116
*/
117
goog.functions.fail = function(err) {
118
'use strict';
119
return function() {
120
'use strict';
121
throw err;
122
};
123
};
124
125
126
/**
127
* Given a function, create a function that keeps opt_numArgs arguments and
128
* silently discards all additional arguments.
129
* @param {Function} f The original function.
130
* @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0.
131
* @return {!Function} A version of f that only keeps the first opt_numArgs
132
* arguments.
133
*/
134
goog.functions.lock = function(f, opt_numArgs) {
135
'use strict';
136
opt_numArgs = opt_numArgs || 0;
137
return function() {
138
'use strict';
139
const self = /** @type {*} */ (this);
140
return f.apply(self, Array.prototype.slice.call(arguments, 0, opt_numArgs));
141
};
142
};
143
144
145
/**
146
* Creates a function that returns its nth argument.
147
* @param {number} n The position of the return argument.
148
* @return {!Function} A new function.
149
*/
150
goog.functions.nth = function(n) {
151
'use strict';
152
return function() {
153
'use strict';
154
return arguments[n];
155
};
156
};
157
158
159
/**
160
* Like goog.partial(), except that arguments are added after arguments to the
161
* returned function.
162
*
163
* Usage:
164
* function f(arg1, arg2, arg3, arg4) { ... }
165
* var g = goog.functions.partialRight(f, arg3, arg4);
166
* g(arg1, arg2);
167
*
168
* @param {!Function} fn A function to partially apply.
169
* @param {...*} var_args Additional arguments that are partially applied to fn
170
* at the end.
171
* @return {!Function} A partially-applied form of the function goog.partial()
172
* was invoked as a method of.
173
*/
174
goog.functions.partialRight = function(fn, var_args) {
175
'use strict';
176
const rightArgs = Array.prototype.slice.call(arguments, 1);
177
return function() {
178
'use strict';
179
// Even in strict mode, IE10/11 and Edge (non-Chromium) use global context
180
// when free-calling functions. To catch cases where people were using this
181
// erroneously, we explicitly change the context to undefined to match
182
// strict mode specifications.
183
let self = /** @type {*} */ (this);
184
if (self === goog.global) {
185
self = undefined;
186
}
187
const newArgs = Array.prototype.slice.call(arguments);
188
newArgs.push.apply(newArgs, rightArgs);
189
return fn.apply(self, newArgs);
190
};
191
};
192
193
194
/**
195
* Given a function, create a new function that swallows its return value
196
* and replaces it with a new one.
197
* @param {Function} f A function.
198
* @param {T} retValue A new return value.
199
* @return {function(...?):T} A new function.
200
* @template T
201
*/
202
goog.functions.withReturnValue = function(f, retValue) {
203
'use strict';
204
return goog.functions.sequence(f, goog.functions.constant(retValue));
205
};
206
207
208
/**
209
* Creates a function that returns whether its argument equals the given value.
210
*
211
* Example:
212
* var key = goog.object.findKey(obj, goog.functions.equalTo('needle'));
213
*
214
* @param {*} value The value to compare to.
215
* @param {boolean=} opt_useLooseComparison Whether to use a loose (==)
216
* comparison rather than a strict (===) one. Defaults to false.
217
* @return {function(*):boolean} The new function.
218
*/
219
goog.functions.equalTo = function(value, opt_useLooseComparison) {
220
'use strict';
221
return function(other) {
222
'use strict';
223
return opt_useLooseComparison ? (value == other) : (value === other);
224
};
225
};
226
227
228
/**
229
* Creates the composition of the functions passed in.
230
* For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).
231
* @param {function(...?):T} fn The final function.
232
* @param {...Function} var_args A list of functions.
233
* @return {function(...?):T} The composition of all inputs.
234
* @template T
235
*/
236
goog.functions.compose = function(fn, var_args) {
237
'use strict';
238
const functions = arguments;
239
const length = functions.length;
240
return function() {
241
'use strict';
242
const self = /** @type {*} */ (this);
243
let result;
244
if (length) {
245
result = functions[length - 1].apply(self, arguments);
246
}
247
248
for (let i = length - 2; i >= 0; i--) {
249
result = functions[i].call(self, result);
250
}
251
return result;
252
};
253
};
254
255
256
/**
257
* Creates a function that calls the functions passed in in sequence, and
258
* returns the value of the last function. For example,
259
* (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).
260
* @param {...Function} var_args A list of functions.
261
* @return {!Function} A function that calls all inputs in sequence.
262
*/
263
goog.functions.sequence = function(var_args) {
264
'use strict';
265
const functions = arguments;
266
const length = functions.length;
267
return function() {
268
'use strict';
269
const self = /** @type {*} */ (this);
270
let result;
271
for (let i = 0; i < length; i++) {
272
result = functions[i].apply(self, arguments);
273
}
274
return result;
275
};
276
};
277
278
279
/**
280
* Creates a function that returns true if each of its components evaluates
281
* to true. The components are evaluated in order, and the evaluation will be
282
* short-circuited as soon as a function returns false.
283
* For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).
284
* @param {...Function} var_args A list of functions.
285
* @return {function(...?):boolean} A function that ANDs its component
286
* functions.
287
*/
288
goog.functions.and = function(var_args) {
289
'use strict';
290
const functions = arguments;
291
const length = functions.length;
292
return function() {
293
'use strict';
294
const self = /** @type {*} */ (this);
295
for (let i = 0; i < length; i++) {
296
if (!functions[i].apply(self, arguments)) {
297
return false;
298
}
299
}
300
return true;
301
};
302
};
303
304
305
/**
306
* Creates a function that returns true if any of its components evaluates
307
* to true. The components are evaluated in order, and the evaluation will be
308
* short-circuited as soon as a function returns true.
309
* For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).
310
* @param {...Function} var_args A list of functions.
311
* @return {function(...?):boolean} A function that ORs its component
312
* functions.
313
*/
314
goog.functions.or = function(var_args) {
315
'use strict';
316
const functions = arguments;
317
const length = functions.length;
318
return function() {
319
'use strict';
320
const self = /** @type {*} */ (this);
321
for (let i = 0; i < length; i++) {
322
if (functions[i].apply(self, arguments)) {
323
return true;
324
}
325
}
326
return false;
327
};
328
};
329
330
331
/**
332
* Creates a function that returns the Boolean opposite of a provided function.
333
* For example, (goog.functions.not(f))(x) is equivalent to !f(x).
334
* @param {!Function} f The original function.
335
* @return {function(...?):boolean} A function that delegates to f and returns
336
* opposite.
337
*/
338
goog.functions.not = function(f) {
339
'use strict';
340
return function() {
341
'use strict';
342
const self = /** @type {*} */ (this);
343
return !f.apply(self, arguments);
344
};
345
};
346
347
348
/**
349
* Generic factory function to construct an object given the constructor
350
* and the arguments. Intended to be bound to create object factories.
351
*
352
* Example:
353
*
354
* var factory = goog.partial(goog.functions.create, Class);
355
*
356
* @param {function(new:T, ...)} constructor The constructor for the Object.
357
* @param {...*} var_args The arguments to be passed to the constructor.
358
* @return {T} A new instance of the class given in `constructor`.
359
* @template T
360
* @deprecated This function does not work with ES6 class constructors. Use
361
* arrow functions + spread args instead.
362
*/
363
goog.functions.create = function(constructor, var_args) {
364
'use strict';
365
/**
366
* @constructor
367
* @final
368
*/
369
const temp = function() {};
370
temp.prototype = constructor.prototype;
371
372
// obj will have constructor's prototype in its chain and
373
// 'obj instanceof constructor' will be true.
374
const obj = new temp();
375
376
// obj is initialized by constructor.
377
// arguments is only array-like so lacks shift(), but can be used with
378
// the Array prototype function.
379
constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
380
return obj;
381
};
382
383
384
/**
385
* @define {boolean} Whether the return value cache should be used.
386
* This should only be used to disable caches when testing.
387
*/
388
goog.functions.CACHE_RETURN_VALUE =
389
goog.define('goog.functions.CACHE_RETURN_VALUE', true);
390
391
392
/**
393
* Gives a wrapper function that caches the return value of a parameterless
394
* function when first called.
395
*
396
* When called for the first time, the given function is called and its
397
* return value is cached (thus this is only appropriate for idempotent
398
* functions). Subsequent calls will return the cached return value. This
399
* allows the evaluation of expensive functions to be delayed until first used.
400
*
401
* To cache the return values of functions with parameters, see goog.memoize.
402
*
403
* @param {function():T} fn A function to lazily evaluate.
404
* @return {function():T} A wrapped version the function.
405
* @template T
406
*/
407
goog.functions.cacheReturnValue = function(fn) {
408
'use strict';
409
let called = false;
410
let value;
411
412
return function() {
413
'use strict';
414
if (!goog.functions.CACHE_RETURN_VALUE) {
415
return fn();
416
}
417
418
if (!called) {
419
value = fn();
420
called = true;
421
}
422
423
return value;
424
};
425
};
426
427
428
/**
429
* Wraps a function to allow it to be called, at most, once. All
430
* additional calls are no-ops.
431
*
432
* This is particularly useful for initialization functions
433
* that should be called, at most, once.
434
*
435
* @param {function():*} f Function to call.
436
* @return {function():undefined} Wrapped function.
437
*/
438
goog.functions.once = function(f) {
439
'use strict';
440
// Keep a reference to the function that we null out when we're done with
441
// it -- that way, the function can be GC'd when we're done with it.
442
let inner = f;
443
return function() {
444
'use strict';
445
if (inner) {
446
const tmp = inner;
447
inner = null;
448
tmp();
449
}
450
};
451
};
452
453
454
/**
455
* Wraps a function to allow it to be called, at most, once per interval
456
* (specified in milliseconds). If the wrapper function is called N times within
457
* that interval, only the Nth call will go through.
458
*
459
* This is particularly useful for batching up repeated actions where the
460
* last action should win. This can be used, for example, for refreshing an
461
* autocomplete pop-up every so often rather than updating with every keystroke,
462
* since the final text typed by the user is the one that should produce the
463
* final autocomplete results. For more stateful debouncing with support for
464
* pausing, resuming, and canceling debounced actions, use
465
* `goog.async.Debouncer`.
466
*
467
* @param {function(this:SCOPE, ...?)} f Function to call.
468
* @param {number} interval Interval over which to debounce. The function will
469
* only be called after the full interval has elapsed since the last call.
470
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
471
* @return {function(...?): undefined} Wrapped function.
472
* @template SCOPE
473
*/
474
goog.functions.debounce = function(f, interval, opt_scope) {
475
'use strict';
476
let timeout = 0;
477
return /** @type {function(...?)} */ (function(var_args) {
478
'use strict';
479
goog.global.clearTimeout(timeout);
480
const args = arguments;
481
timeout = goog.global.setTimeout(function() {
482
'use strict';
483
f.apply(opt_scope, args);
484
}, interval);
485
});
486
};
487
488
489
/**
490
* Wraps a function to allow it to be called, at most, once per interval
491
* (specified in milliseconds). If the wrapper function is called N times in
492
* that interval, both the 1st and the Nth calls will go through.
493
*
494
* This is particularly useful for limiting repeated user requests where the
495
* the last action should win, but you also don't want to wait until the end of
496
* the interval before sending a request out, as it leads to a perception of
497
* slowness for the user.
498
*
499
* @param {function(this:SCOPE, ...?)} f Function to call.
500
* @param {number} interval Interval over which to throttle. The function can
501
* only be called once per interval.
502
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
503
* @return {function(...?): undefined} Wrapped function.
504
* @template SCOPE
505
*/
506
goog.functions.throttle = function(f, interval, opt_scope) {
507
'use strict';
508
let timeout = 0;
509
let shouldFire = false;
510
let storedArgs = [];
511
512
const handleTimeout = function() {
513
'use strict';
514
timeout = 0;
515
if (shouldFire) {
516
shouldFire = false;
517
fire();
518
}
519
};
520
521
const fire = function() {
522
'use strict';
523
timeout = goog.global.setTimeout(handleTimeout, interval);
524
let args = storedArgs;
525
storedArgs = []; // Avoid a space leak by clearing stored arguments.
526
f.apply(opt_scope, args);
527
};
528
529
return /** @type {function(...?)} */ (function(var_args) {
530
'use strict';
531
storedArgs = arguments;
532
if (!timeout) {
533
fire();
534
} else {
535
shouldFire = true;
536
}
537
});
538
};
539
540
541
/**
542
* Wraps a function to allow it to be called, at most, once per interval
543
* (specified in milliseconds). If the wrapper function is called N times within
544
* that interval, only the 1st call will go through.
545
*
546
* This is particularly useful for limiting repeated user requests where the
547
* first request is guaranteed to have all the data required to perform the
548
* final action, so there's no need to wait until the end of the interval before
549
* sending the request out.
550
*
551
* @param {function(this:SCOPE, ...?)} f Function to call.
552
* @param {number} interval Interval over which to rate-limit. The function will
553
* only be called once per interval, and ignored for the remainer of the
554
* interval.
555
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
556
* @return {function(...?): undefined} Wrapped function.
557
* @template SCOPE
558
*/
559
goog.functions.rateLimit = function(f, interval, opt_scope) {
560
'use strict';
561
let timeout = 0;
562
563
const handleTimeout = function() {
564
'use strict';
565
timeout = 0;
566
};
567
568
return /** @type {function(...?)} */ (function(var_args) {
569
'use strict';
570
if (!timeout) {
571
timeout = goog.global.setTimeout(handleTimeout, interval);
572
f.apply(opt_scope, arguments);
573
}
574
});
575
};
576
577
/**
578
* Returns true if the specified value is a function.
579
* @param {*} val Variable to test.
580
* @return {boolean} Whether variable is a function.
581
*/
582
goog.functions.isFunction = (val) => {
583
return typeof val === 'function';
584
};
585
586