lib/goog/functions/functions.js

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/**
16 * @fileoverview Utilities for creating functions. Loosely inspired by the
17 * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8.
18 *
19 * @author nicksantos@google.com (Nick Santos)
20 */
21
22
23goog.provide('goog.functions');
24
25
26/**
27 * Creates a function that always returns the same value.
28 * @param {T} retValue The value to return.
29 * @return {function():T} The new function.
30 * @template T
31 */
32goog.functions.constant = function(retValue) {
33 return function() {
34 return retValue;
35 };
36};
37
38
39/**
40 * Always returns false.
41 * @type {function(...): boolean}
42 */
43goog.functions.FALSE = goog.functions.constant(false);
44
45
46/**
47 * Always returns true.
48 * @type {function(...): boolean}
49 */
50goog.functions.TRUE = goog.functions.constant(true);
51
52
53/**
54 * Always returns NULL.
55 * @type {function(...): null}
56 */
57goog.functions.NULL = goog.functions.constant(null);
58
59
60/**
61 * A simple function that returns the first argument of whatever is passed
62 * into it.
63 * @param {T=} opt_returnValue The single value that will be returned.
64 * @param {...*} var_args Optional trailing arguments. These are ignored.
65 * @return {T} The first argument passed in, or undefined if nothing was passed.
66 * @template T
67 */
68goog.functions.identity = function(opt_returnValue, var_args) {
69 return opt_returnValue;
70};
71
72
73/**
74 * Creates a function that always throws an error with the given message.
75 * @param {string} message The error message.
76 * @return {!Function} The error-throwing function.
77 */
78goog.functions.error = function(message) {
79 return function() {
80 throw Error(message);
81 };
82};
83
84
85/**
86 * Creates a function that throws the given object.
87 * @param {*} err An object to be thrown.
88 * @return {!Function} The error-throwing function.
89 */
90goog.functions.fail = function(err) {
91 return function() {
92 throw err;
93 }
94};
95
96
97/**
98 * Given a function, create a function that keeps opt_numArgs arguments and
99 * silently discards all additional arguments.
100 * @param {Function} f The original function.
101 * @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0.
102 * @return {!Function} A version of f that only keeps the first opt_numArgs
103 * arguments.
104 */
105goog.functions.lock = function(f, opt_numArgs) {
106 opt_numArgs = opt_numArgs || 0;
107 return function() {
108 return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs));
109 };
110};
111
112
113/**
114 * Creates a function that returns its nth argument.
115 * @param {number} n The position of the return argument.
116 * @return {!Function} A new function.
117 */
118goog.functions.nth = function(n) {
119 return function() {
120 return arguments[n];
121 };
122};
123
124
125/**
126 * Given a function, create a new function that swallows its return value
127 * and replaces it with a new one.
128 * @param {Function} f A function.
129 * @param {T} retValue A new return value.
130 * @return {function(...[?]):T} A new function.
131 * @template T
132 */
133goog.functions.withReturnValue = function(f, retValue) {
134 return goog.functions.sequence(f, goog.functions.constant(retValue));
135};
136
137
138/**
139 * Creates a function that returns whether its arguement equals the given value.
140 *
141 * Example:
142 * var key = goog.object.findKey(obj, goog.functions.equalTo('needle'));
143 *
144 * @param {*} value The value to compare to.
145 * @param {boolean=} opt_useLooseComparison Whether to use a loose (==)
146 * comparison rather than a strict (===) one. Defaults to false.
147 * @return {function(*):boolean} The new function.
148 */
149goog.functions.equalTo = function(value, opt_useLooseComparison) {
150 return function(other) {
151 return opt_useLooseComparison ? (value == other) : (value === other);
152 };
153};
154
155
156/**
157 * Creates the composition of the functions passed in.
158 * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).
159 * @param {function(...[?]):T} fn The final function.
160 * @param {...Function} var_args A list of functions.
161 * @return {function(...[?]):T} The composition of all inputs.
162 * @template T
163 */
164goog.functions.compose = function(fn, var_args) {
165 var functions = arguments;
166 var length = functions.length;
167 return function() {
168 var result;
169 if (length) {
170 result = functions[length - 1].apply(this, arguments);
171 }
172
173 for (var i = length - 2; i >= 0; i--) {
174 result = functions[i].call(this, result);
175 }
176 return result;
177 };
178};
179
180
181/**
182 * Creates a function that calls the functions passed in in sequence, and
183 * returns the value of the last function. For example,
184 * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).
185 * @param {...Function} var_args A list of functions.
186 * @return {!Function} A function that calls all inputs in sequence.
187 */
188goog.functions.sequence = function(var_args) {
189 var functions = arguments;
190 var length = functions.length;
191 return function() {
192 var result;
193 for (var i = 0; i < length; i++) {
194 result = functions[i].apply(this, arguments);
195 }
196 return result;
197 };
198};
199
200
201/**
202 * Creates a function that returns true if each of its components evaluates
203 * to true. The components are evaluated in order, and the evaluation will be
204 * short-circuited as soon as a function returns false.
205 * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).
206 * @param {...Function} var_args A list of functions.
207 * @return {function(...[?]):boolean} A function that ANDs its component
208 * functions.
209 */
210goog.functions.and = function(var_args) {
211 var functions = arguments;
212 var length = functions.length;
213 return function() {
214 for (var i = 0; i < length; i++) {
215 if (!functions[i].apply(this, arguments)) {
216 return false;
217 }
218 }
219 return true;
220 };
221};
222
223
224/**
225 * Creates a function that returns true if any of its components evaluates
226 * to true. The components are evaluated in order, and the evaluation will be
227 * short-circuited as soon as a function returns true.
228 * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).
229 * @param {...Function} var_args A list of functions.
230 * @return {function(...[?]):boolean} A function that ORs its component
231 * functions.
232 */
233goog.functions.or = function(var_args) {
234 var functions = arguments;
235 var length = functions.length;
236 return function() {
237 for (var i = 0; i < length; i++) {
238 if (functions[i].apply(this, arguments)) {
239 return true;
240 }
241 }
242 return false;
243 };
244};
245
246
247/**
248 * Creates a function that returns the Boolean opposite of a provided function.
249 * For example, (goog.functions.not(f))(x) is equivalent to !f(x).
250 * @param {!Function} f The original function.
251 * @return {function(...[?]):boolean} A function that delegates to f and returns
252 * opposite.
253 */
254goog.functions.not = function(f) {
255 return function() {
256 return !f.apply(this, arguments);
257 };
258};
259
260
261/**
262 * Generic factory function to construct an object given the constructor
263 * and the arguments. Intended to be bound to create object factories.
264 *
265 * Example:
266 *
267 * var factory = goog.partial(goog.functions.create, Class);
268 *
269 * @param {function(new:T, ...)} constructor The constructor for the Object.
270 * @param {...*} var_args The arguments to be passed to the constructor.
271 * @return {!T} A new instance of the class given in {@code constructor}.
272 * @template T
273 */
274goog.functions.create = function(constructor, var_args) {
275 /**
276 * @constructor
277 * @final
278 */
279 var temp = function() {};
280 temp.prototype = constructor.prototype;
281
282 // obj will have constructor's prototype in its chain and
283 // 'obj instanceof constructor' will be true.
284 var obj = new temp();
285
286 // obj is initialized by constructor.
287 // arguments is only array-like so lacks shift(), but can be used with
288 // the Array prototype function.
289 constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
290 return obj;
291};
292
293
294/**
295 * @define {boolean} Whether the return value cache should be used.
296 * This should only be used to disable caches when testing.
297 */
298goog.define('goog.functions.CACHE_RETURN_VALUE', true);
299
300
301/**
302 * Gives a wrapper function that caches the return value of a parameterless
303 * function when first called.
304 *
305 * When called for the first time, the given function is called and its
306 * return value is cached (thus this is only appropriate for idempotent
307 * functions). Subsequent calls will return the cached return value. This
308 * allows the evaluation of expensive functions to be delayed until first used.
309 *
310 * To cache the return values of functions with parameters, see goog.memoize.
311 *
312 * @param {!function():T} fn A function to lazily evaluate.
313 * @return {!function():T} A wrapped version the function.
314 * @template T
315 */
316goog.functions.cacheReturnValue = function(fn) {
317 var called = false;
318 var value;
319
320 return function() {
321 if (!goog.functions.CACHE_RETURN_VALUE) {
322 return fn();
323 }
324
325 if (!called) {
326 value = fn();
327 called = true;
328 }
329
330 return value;
331 }
332};