# 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 at6//7//      http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// 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 and13// limitations under the License.1415/**16 * @fileoverview Utilities for creating functions. Loosely inspired by the17 * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8.18 *19 * @author nicksantos@google.com (Nick Santos)20 */212223goog.provide('goog.functions');242526/**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 T31 */32goog.functions.constant = function(retValue) {33  return function() {34    return retValue;35  };36};373839/**40 * Always returns false.41 * @type {function(...): boolean}42 */43goog.functions.FALSE = goog.functions.constant(false);444546/**47 * Always returns true.48 * @type {function(...): boolean}49 */50goog.functions.TRUE = goog.functions.constant(true);515253/**54 * Always returns NULL.55 * @type {function(...): null}56 */57goog.functions.NULL = goog.functions.constant(null);585960/**61 * A simple function that returns the first argument of whatever is passed62 * 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 T67 */68goog.functions.identity = function(opt_returnValue, var_args) {69  return opt_returnValue;70};717273/**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};838485/**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};959697/**98 * Given a function, create a function that keeps opt_numArgs arguments and99 * 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_numArgs103 *     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};111112113/**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};123124125/**126 * Given a function, create a new function that swallows its return value127 * 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 T132 */133goog.functions.withReturnValue = function(f, retValue) {134  return goog.functions.sequence(f, goog.functions.constant(retValue));135};136137138/**139 * Creates the composition of the functions passed in.140 * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).141 * @param {function(...[?]):T} fn The final function.142 * @param {...Function} var_args A list of functions.143 * @return {function(...[?]):T} The composition of all inputs.144 * @template T145 */146goog.functions.compose = function(fn, var_args) {147  var functions = arguments;148  var length = functions.length;149  return function() {150    var result;151    if (length) {152      result = functions[length - 1].apply(this, arguments);153    }154155    for (var i = length - 2; i >= 0; i--) {156      result = functions[i].call(this, result);157    }158    return result;159  };160};161162163/**164 * Creates a function that calls the functions passed in in sequence, and165 * returns the value of the last function. For example,166 * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).167 * @param {...Function} var_args A list of functions.168 * @return {!Function} A function that calls all inputs in sequence.169 */170goog.functions.sequence = function(var_args) {171  var functions = arguments;172  var length = functions.length;173  return function() {174    var result;175    for (var i = 0; i < length; i++) {176      result = functions[i].apply(this, arguments);177    }178    return result;179  };180};181182183/**184 * Creates a function that returns true if each of its components evaluates185 * to true. The components are evaluated in order, and the evaluation will be186 * short-circuited as soon as a function returns false.187 * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).188 * @param {...Function} var_args A list of functions.189 * @return {function(...[?]):boolean} A function that ANDs its component190 *      functions.191 */192goog.functions.and = function(var_args) {193  var functions = arguments;194  var length = functions.length;195  return function() {196    for (var i = 0; i < length; i++) {197      if (!functions[i].apply(this, arguments)) {198        return false;199      }200    }201    return true;202  };203};204205206/**207 * Creates a function that returns true if any of its components evaluates208 * to true. The components are evaluated in order, and the evaluation will be209 * short-circuited as soon as a function returns true.210 * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).211 * @param {...Function} var_args A list of functions.212 * @return {function(...[?]):boolean} A function that ORs its component213 *    functions.214 */215goog.functions.or = function(var_args) {216  var functions = arguments;217  var length = functions.length;218  return function() {219    for (var i = 0; i < length; i++) {220      if (functions[i].apply(this, arguments)) {221        return true;222      }223    }224    return false;225  };226};227228229/**230 * Creates a function that returns the Boolean opposite of a provided function.231 * For example, (goog.functions.not(f))(x) is equivalent to !f(x).232 * @param {!Function} f The original function.233 * @return {function(...[?]):boolean} A function that delegates to f and returns234 * opposite.235 */236goog.functions.not = function(f) {237  return function() {238    return !f.apply(this, arguments);239  };240};241242243/**244 * Generic factory function to construct an object given the constructor245 * and the arguments. Intended to be bound to create object factories.246 *247 * Callers should cast the result to the appropriate type for proper type248 * checking by the compiler.249 * @param {!Function} constructor The constructor for the Object.250 * @param {...*} var_args The arguments to be passed to the constructor.251 * @return {!Object} A new instance of the class given in {@code constructor}.252 */253goog.functions.create = function(constructor, var_args) {254  /**255 * @constructor256 * @final257 */258  var temp = function() {};259  temp.prototype = constructor.prototype;260261  // obj will have constructor's prototype in its chain and262  // 'obj instanceof constructor' will be true.263  var obj = new temp();264265  // obj is initialized by constructor.266  // arguments is only array-like so lacks shift(), but can be used with267  // the Array prototype function.268  constructor.apply(obj, Array.prototype.slice.call(arguments, 1));269  return obj;270};271272273/**274 * @define {boolean} Whether the return value cache should be used.275 *    This should only be used to disable caches when testing.276 */277goog.define('goog.functions.CACHE_RETURN_VALUE', true);278279280/**281 * Gives a wrapper function that caches the return value of a parameterless282 * function when first called.283 *284 * When called for the first time, the given function is called and its285 * return value is cached (thus this is only appropriate for idempotent286 * functions).  Subsequent calls will return the cached return value. This287 * allows the evaluation of expensive functions to be delayed until first used.288 *289 * To cache the return values of functions with parameters, see goog.memoize.290 *291 * @param {!function():T} fn A function to lazily evaluate.292 * @return {!function():T} A wrapped version the function.293 * @template T294 */295goog.functions.cacheReturnValue = function(fn) {296  var called = false;297  var value;298299  return function() {300    if (!goog.functions.CACHE_RETURN_VALUE) {301      return fn();302    }303304    if (!called) {305      value = fn();306      called = true;307    }308309    return value;310  }311};