The brass buckles on Underscore's utility belt - a contributors' library for Underscore.
While Underscore provides a bevy of useful tools to support functional programming in JavaScript, it can't (and shouldn't) be everything to everyone. Underscore-contrib is intended as a home for functions that, for various reasons, don't belong in Underscore proper. In particular, it aims to be:
First, you'll need Underscore version 1.6.0 or higher. Then you can grab the relevant underscore-contrib sub-libraries and simply add something like the following to your pages:
<script type="text/javascript" src="underscore.js"></script>
<script type="text/javascript" src="underscore.object.builders.js"></script>
At the moment there are no cross-contrib dependencies (i.e. each sub-library can stand by itself), but that may change in the future.
Using contrib in Node is very simple. Just install it with npm:
npm install underscore-contrib --save
Then require it within your project like so:
var _ = require('underscore-contrib');
The _
variable will be a copy of Underscore with contrib's methods already
mixed in.
_.contrib is open sourced under the MIT license.
The _.contrib library currently contains a number of related capabilities, aggregated into the following files.
true
or false
based on some criteriaThe links above are to the annotated source code. Full-blown _.contrib documentation is in the works. Contributors welcomed.
Functions to build arrays. View Annotated Source
Signature: _.cat(... arrays:Array ...)
The _.cat
function provides a way to concatenate zero or more heterogeneous arrays into one.
_.cat(); // 0-args
//=> []
_.cat([]); // 1-arg, empty array
//=> []
_.cat([1,2,3]); // 1-arg
//=> [1,2,3]
_.cat([1,2,3],[4,5,6]); // 2-args
//=> [1,2,3,4,5,6]
_.cat([1,2,3],[4,5,6],[7]); // 3+ args
//=> [1,2,3,4,5,6,7]
Not every argument to _.cat
needs to be an array; other types are accepted.
Signature: _.cat(... elems:Any ...)
_.cat(1,[2],3,4); // mixed args
//=> [1,2,3,4]
The _.cat
function will also work with the arguments
object as if it were an array.
Signature: _.cat(... elems:Arguments ...)
function f(){ return _.cat(arguments, 4,5,6); }
f(1,2,3);
//=> [1,2,3,4,5,6]
The _.chunk
function, by default, accepts an array and a number and splits and returns a new array representing the original array split into some number of arrays of the given size:
_.chunk([0,1,2,3], 2);
//=> , [[0,1],[2,3]]
If the original array cannot completely fulfill the chunk scheme then the array returned will drop the undersized final chunk:
_.chunk([0,1,2,3,4], 2);
//=> , [[0,1],[2,3]]
You can pass an optional third argument to _.chunk
to pad out the final array chunk should it fall short. If the value given as the third argument is not an array then it is repeated the needed number of times:
_.chunk([0,1,2,3,4], 3, '_');
//=> , [[0,1,2],[3,'_','_']]
If you given an array as the optional third argument then that array is used to pad in-place as needed:
_.chunk([0,1,2,3,4], 3, ['a', 'b']);
//=> , [[0,1,2],[3,'a','b']]
The _.chunkAll
function is similar to _.chunk
except for the following. First, _.chunkAll
will never drop short chunks from the end:
_.chunkAll([0,1,2,3,4], 3);
//=> , [[0,1,2],[3]]
Also, _.chunkAll
takes an optional third argument signifying that paritions should be built from skipped regions:
_.chunkAll(_.range(1), 2, 4);
//=> [[0,1],[4,5],[8,9]]
Signature: _.cons(head:Any, tail:Array)
The _.cons
function provides a way to "construct" a new array by taking some element and putting it at the front of another array.
_.cons(0, []);
//=> [0]
_.cons(1, [2]);
//=> [1,2]
_.cons([0], [1,2,3]);
//=> [0,1,2,3]
The _.cons
function also can be used to create pairs if the second argument is not an array.
Signature: _.cons(head:Any, tail:Any)
_.cons(1, 2);
//=> [1,2]
_.cons([1], 2);
//=> [[1],2]
Finally, _.cons
will operate with the arguments
object.
Signature: _.cons(head:Any, tail:Arguments)
function f() { return _.cons(0, arguments) }
f(1,2,3);
//=> [0,1,2,3]
The _.cycle
function takes an integer value used to build an array of that size containing the number of iterations through the given array, strung end-to-end as many times as needed. An example is probably more instructive:
_.cycle(5, [1,2,3]);
//=> [1,2,3,1,2]
The _.interpose
function takes an array and an element and returns a new array with the given element inserted betwixt every element in the original array:
_.interpose([1,2,3], 0);
//=> [1,0,2,0,3]
If there are no betweens (i.e. empty and single-element arrays), then the original array is returned:
_.interpose([1], 0);
//=> [1]
_.interpose([], 0);
//=> []
The _.iterateUntil
function takes a function used as a result generator, a function used as a stop-check and a seed value and returns an array of each generated result. The operation of _.iterateUntil
is such that the result generator is passed the seed to start and each subsequent result which will continue until a result fails the check function (i.e. returns falsey). An example is best:
var dec = function(n) { return n - 1; };
var isPos = function(n) { return n > 0; };
The dec
result generator takes a number and decrements it by one. The isPos
predicate takes a number and returns true
if it's positive. Using these two functions you can build an array of every number from 6
to 0
, inclusive:
_.iterateUntil(dec, isPos, 6);
//=> [5,4,3,2,1]
That is, the array only contains every number from 5
down to 1
because when the result of dec
got to 0
the isPos
check failed (i.e. went falsey) thus terminating the execution.
The _.keepIndexed
function takes an array and a function and returns a new array filled with the non-null return results of the given function on the elements or keys in the given array:
_.keepIndexed([1,2,3], function(k) {
return i === 1 || i === 2;
});
//=> [false, true, true]
If you return either null
or undefined
then the result is dropped from the resulting array:
_.keepIndexed(['a','b','c'], function(k, v) {
if (k === 1) return v;
});
//=> ['b']
There are times when a mapping operation produces results contained in arrays, but the final result should be flattened one level. For these circumstances you can use _.mapcat
to produce results:
var array = [1,2,null,4,undefined,6];
var errors = _.mapcat(array, function(e,i) {
if (e == null) {
return ["Element @" + i + " is bad"];
}
else {
return [];
}
});
Inspecting the contents of errors
shows:
["Element @2 is bad", "Element @4 is bad"]
The _.mapcat
function is equivalent to _.cat.apply(array, _.map(array,fun))
.
The _.reductions
function is similar to Underscore's builtin _.reduce
function except that it returns an array of every intermediate value in the folding operation:
_.reductions([1,2,3,4,5], function(agg, n) {
return agg + n;
}, 0);
//=> [1,3,6,10,15]
The last element in the array returned from _.reductions
is the answer that you would get if you had just chosen to use _.reduce
.
Signature: _.repeat(t:Integer, value:Any)
The _.repeat
function takes an integer value used to build an array of that size containing the value given:
_.repeat(5, 'a');
//=> ['a','a','a','a','a']
The _.splitAt
function takes an array and a numeric index and returns a new array with two embedded arrays representing a split of the original array at the index provided:
_.splitAt([1,2,3,4,5], 2);
//=> [[1,2],[3,4,5]]
_.splitAt([1,2,3,4,5], 0);
//=> [[],[1,2,3,4,5]]
The operation of _.splitAt
is safe if the index provided is outside the range of legal indices:
_.splitAt([1,2,3,4,5], 20000);
//=> [[1,2,3,4,5],[]]
_.splitAt([1,2,3,4,5], -1000);
//=> [[],[1,2,3,4,5]]
_.splitAt([], 0);
//=> [[],[]]
The _.takeSkipping
function takes an array and a number and returns a new array containing every nth element in the original array:
_.takeSkipping(_.range(10), 2);
//=> [0,2,4,6,8]
The _.takeSkipping
function is safe against numbers larger or smaller than the array size:
_.takeSkipping(_.range(10), 100000);
//=> [0]
_.takeSkipping(_.range(10), -100);
//=> []
The _.weave
function works similarly to _.interpose
(shown above) except that it accepts an array used as the interposition values. In other words, _.weave
takes two arrays and returns a new array with the original elements woven together. An example would help:
_.weave(['a','b','c'], [1,2,3]);
//=> ['a',1,'b',2,'c',3]
The array returned from _.weave
will be as long as the longest array given with the woven entries stopping according to the shortest array:
_.weave(['a','b','c'], [1]);
//=> ['a',1,'b','c']
The _.interleave
function is an alias for _.weave
.
Functions to take things from arrays. View Annotated Source
Signature: _.best(array:Array, fun:Function)
Returns the "best" value in an array based on the result of a given function.
_.best([1, 2, 3, 4, 5], function(x, y) {
return x > y;
});
//=> 5
Signature: _.dropWhile(array:Array, pred:Function)
Drops elements for which the given function returns a truthy value.
_.dropWhile([-2,-1,0,1,2], isNeg);
//=> [0,1,2]
Signature: _.keep(array:Array, fun:Function)
Returns an array of existy results of a function over a source array.
_.keep([1, 2, 3, 4, 5], function(val) {
if (val % 3 === 0) {
return val;
}
});
// => [3]
Signature: _.nth(array:Array, index:Number[, guard:Any])
The _.nth
function is a convenience for the equivalent array[n]
. The
optional guard
value allows _.nth
to work correctly as a callback for
_.map
.
_.nth(['a','b','c'], 2);
//=> 'c'
If given an index out of bounds then _.nth
will return undefined
:
_.nth(['a','b','c'], 2000);
//=> undefined
The _.nth
function can also be used in conjunction with _.map
and _.compact
like so:
var b = [['a'],['b'],[]];
_.compact(_.map(b, function(e) { return _.nth(e,0) }));
//=> ['a','b']
If wrapping a function around _.nth
is too tedious or you'd like to partially apply the index then Underscore-contrib offers any of _.flip2
, _.fix
or rcurry2
to solve this.
Signature: _.keep(array:Array, fun:Function)
Takes an array and partitions it into sub-arrays as the given predicate changes truth sense.
_.partitionBy([1,2,2,3,1,1,5], _.isEven);
// => [[1],[2,2],[3,1,1,5]]
_.partitionBy([1,2,2,3,1,1,5], _.identity);
// => [[1],[2,2],[3],[1,1],[5]]
Signature: _.second(array:Array, index:Number[, guard:Any])
The _.second
function is a convenience for the equivalent array[1]
. The
optional guard
value allows _.second
to work correctly as a callback for
_.map
.
_.second(['a','b']);
//=> 'b'
_.map([['a','b'], _.range(10,20)], _.second);
//=> ['b',11]
You can also pass an optional number to the _.second
function to take a number of elements from an array starting with the second element and ending at the given index:
_.second(_.range(10), 5)
//=> [1, 2, 3, 4]
Signature: _.takeWhile(array:Array, pred:Function)
The _.takeWhile
function takes an array and a function and returns a new array containing the first n elements in the original array for which the given function returns a truthy value:
var isNeg = function(n) { return n < 0; };
_.takeWhile([-2,-1,0,1,2], isNeg);
//=> [-2,-1]
Signature: _.third(array:Array, index:Number[, guard:Any])
The _.third
function is a convenience for the equivalent array[2]
. The
optional guard
value allows _.third
to work correctly as a callback for
_.map
.
_.third(['a','b','c']);
//=> 'c'
_.map([['a','b','c'], _.range(10,20)], _.third);
//=> ['c',12]
You can also pass an optional number to the _.third
function to take a number of elements from an array starting with the third element and ending at the given index:
_.third(_.range(10), 5)
//=> [2, 3, 4]
Functions to recursively walk collections which are trees.
Documentation should use Journo formats and standards.
_.walk = walk;
postorder: function(obj, visitor, context)
preorder: function(obj, visitor, context)
walk(obj, visitor, null, context)
map: function(obj, strategy, visitor, context)
pluck: function(obj, propertyName)
pluckRec: function(obj, propertyName)
_.walk.collect = _.walk.map;
Functions which manipulate the way functions work with their arguments.
Signature: _.arity(numberOfArgs:Number, fun:Function)
Returns a new function which is equivalent to fun
, except that the new
function's length
property is equal to numberOfArgs
. This does not limit
the function to using that number of arguments. It's only effect is on the
reported length.
function addAll() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum = sum + arguments[i];
}
return sum;
}
addAll.length
// => 0
var addAllWithFixedLength = _.arity(2, addAll);
addAllWithFixedLength.length
// => 2
addAllWithFixedLength(1, 1, 1, 1);
// => 4
Signature: _.binary(fun:Function)
Returns a new function which accepts only two arguments and passes these
arguments to fun
. Additional arguments are discarded.
function addAll() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum = sum + arguments[i];
}
return sum;
}
var add2 = _.binary(addAll);
add2(1, 1);
// => 2
add2(1, 1, 1, 1);
// => 2
Signature: _.curry(func:Function[, reverse:Boolean])
Returns a curried version of func
. If reverse
is true, arguments will be
processed from right to left.
function add3 (x, y, z) {
return x + y + z;
}
var curried = _.curry(add3);
// => function
curried(1);
// => function
curried(1)(2);
// => function
curried(1)(2)(3);
// => 6
Signature: _.curry2(fun:Function)
Returns a curried version of func
, but will curry exactly two arguments, no
more or less.
function add2 (a, b) {
return a + b;
}
var curried = _.curry2(add2);
// => function
curried(1);
// => function
curried(1)(2);
// => 3
Signature: _.curry3(fun:Function)
Returns a curried version of func
, but will curry exactly three arguments, no
more or less.
function add3 (a, b, c) {
return a + b + c;
}
var curried = _.curry3(add3);
// => function
curried(1);
// => function
curried(1)(2);
// => function
curried(1)(2)(3);
// => 6
Signature: _.fix(fun:Function[, value:Any...])
Fixes the arguments to a function based on the parameter template defined by
the presence of values and the _
placeholder.
function add3 (a, b, c) {
return a + b + c;
}
var fixedFirstAndLast = _.fix(add3, 1, _, 3);
// => function
fixedFirstAndLast(2);
// => 6
fixedFirstAndLast(10);
// => 14
Signature: _.quaternary(fun:Function)
Returns a new function which accepts only four arguments and passes these
arguments to fun
. Additional arguments are discarded.
function addAll() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum = sum + arguments[i];
}
return sum;
}
var add4 = _.quaternary(addAll);
add4(1, 1, 1, 1);
// => 4
add4(1, 1, 1, 1, 1, 1);
// => 4
Signature: _.ternary(fun:Function)
Returns a new function which accepts only three arguments and passes these
arguments to fun
. Additional arguments are discarded.
function addAll() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum = sum + arguments[i];
}
return sum;
}
var add3 = _.ternary(addAll);
add3(1, 1, 1);
// => 3
add3(1, 1, 1, 1, 1, 1);
// => 3
Signature: _.unary(fun:Function)
Returns a new function which accepts only one argument and passes this
argument to fun
. Additional arguments are discarded.
function logArgs() {
console.log(arguments);
}
var logOneArg = _.unary(logArgs);
logOneArg("first");
// => ["first"]
logOneArg("first", "second");
// => ["first"]
Signature: _.rCurry(func:Function)
Returns a curried version of func
where arguments are processed from right
to left.
function divide (a, b) {
return a / b;
}
var curried = _.rCurry(divide);
// => function
curried(1);
// => function
curried(1)(2);
// => 2
curried(2)(1);
// => 0.5
Signature: _.rcurry2(func:Function)
Returns a curried version of func
where a maxium of two arguments are
processed from right to left.
function concat () {
var str = "";
for (var i = 0; i < arguments.length; i++) {
str = str + arguments[i];
}
return str;
}
var curried = _.rcurry2(concat);
// => function
curried("a");
// => function
curried("a")("b");
// => "ba"
Signature: _.rcurry3(func:Function)
Returns a curried version of func
where a maxium of three arguments are
processed from right to left.
function concat () {
var str = "";
for (var i = 0; i < arguments.length; i++) {
str = str + arguments[i];
}
return str;
}
var curried = _.rcurry3(concat);
// => function
curried("a");
// => function
curried("a")("b");
// => function
curried("a")("b")("c");
// => "cba"
Functions that are combinators.
Signature: _.always(value:Any)
Aliases: _.k
Takes value
and returns a function that will always return value
.
var platonicForm = _.always("Eternal & Unchangeable");
platonicForm();
// => "Eternal & Unchangeable"
Signature: _.bound(obj:Object, fname:String)
Returns function property of an object by name, bound to object.
var aristotle = {
name: "Aristotle",
telos: "flourishing",
stateTelos: function() {
return this.name + "'s telos is " + this.telos;
}
};
var stateAristotlesTelos = _.bound(aristotle, "stateTelos");
stateAristotlesTelos();
// => "Aristotle's Telos is flourishing"
Signature: _.comparator(fun:Function)
Takes a binary predicate-like function and returns a comparator function (return
values of -1
, 0
, 1
) which can be used as a callback for _.sort
or
Array.prototype.sort
.
var lessOrEqual = function(x, y) { return x <= y; };
var arr = [0, 1, -2];
arr.sort(_.comparator(lessOrEqual));
// => [-2, 0, 1]
Signature: _.complement(pred:Function)
Returns a function that reverses the sense of a given predicate-like.
function isAugustine (val) {
return val === "Augustine";
}
isNotAugustine = _.complement(isAugustine);
isNotAugustine("Dionysius");
// => True
Signature: _.conjoin(pred:Function...)
Composes multiple predicates into a single predicate that checks all elements of an array for conformance to all of the original predicates.
function startsWithA (val) {
return val[0] === "A";
}
function endsWithE (val) {
return val[val.length - 1] === "e";
}
var names = ["Aristotle", "Aquinas", "Plato", "Augustine"];
var startsAAndEndsE = _.conjoin(startsWithA, endsWithE);
startsAAndEndsE(names);
// => ["Aristotle", "Augustine"]
Signature: _.disjoin(pred:Function...)
Composes multiple predicates into a single predicate that checks all elements of an array for conformance to any of the original predicates.
function startsWithA (val) {
return val[0] === "A";
}
function endsWithE (val) {
return val[val.length - 1] === "e";
}
var names = ["Aristotle", "Aquinas", "Plato", "Augustine"];
var startsAOrEndsE = _.disjoin(startsWithA, endsWithE);
startsAOrEndsE(names);
// => ["Aristotle", "Aquinas", "Augustine"]
Signature: _.juxt(fun:Function...)
Returns a function whose return value is an array of the results of calling each of the original functions with the arguments.
function firstChar (val) {
return val[0];
}
function lastChar (val) {
return val[val.length - 1];
}
var firstAndLastChars = _.juxt(firstChar, lastChar);
firstAndLastChars("Etruria");
// => ["E", "a"]
Signature: _.flip(fun:Function)
Returns a function that works identically to fun
, but accepts the arguments
in reverse order.
function regionCapitol (region, capitol) {
return "The capitol of " + region + " is " + capitol;
}
capitolRegion = _.flip(regionCapitol);
capitolRegion("Thessalonica", "Illyrica");
// => "The capitol of Illyrica is Thessalonica"
Signature: _.flip2(fun:Function)
Returns a function that works identically to fun
, but accepts the first two
arguments in reverse order. The order of all other arguments remains the same.
function regionCapitol (region, capitol) {
return "The capitol of " + region + " is " + capitol;
}
capitolRegion = _.flip2(regionCapitol);
capitolRegion("Thessalonica", "Illyrica");
// => "The capitol of Illyrica is Thessalonica"
Signature: _.fnull(fun:Function[, default:Any...])
Returns a function that protects fun
from receiving non-existy values. Each
subsequent value provided to fnull
acts as the default to the original
fun
should a call receive non-existy values in the defaulted arg slots.
function getLength (val) {
return val.length;
}
safeGetLength = _.fnull(getLength, []);
safeGetLength([1, 2, 3]);
// => 3
safeGetLength(null);
// => 0
Signature: _.functionalize(fun:Function[, default:Any...])
Takes a method-style function (one which uses this
) and pushes this
into the
argument list. The returned function uses its first argument as the
receiver/context of the original function, and the rest of the arguments are
used as the original's entire argument list.
var militaryUnits = {
centuria: "80 men",
cohort: "480 men",
getDescription: function (unitName) {
return this[unitName];
}
};
var getDescription = _.functionalize(militaryUnits.getDescription);
var rulers = {
Leonidas: "King of Sparta",
Augustus: "First Roman Emperor"
};
getDescription(rulers, "Augustus");
// => "First Roman Emperor"
Signature: _.mapArgs(fun:Function)
Takes a target function and returns a new function which accepts a mapping function, which in turn returns a function that will map its arguments before calling the original target function.
function doubleNum (x) { return 2 * x; }
function squareNum (x) { return x * x; }
var squareThenDouble = _.mapArgs(doubleNum)(squareNum);
squareThenDouble(3);
// => 18
Signature: _.mapArgs(mapFun:Function)
Takes a mapping function and returns a new combinator function which will take a target function and return a new version which maps its arguments with the mapping function before executing the body of the target function.
function doubleNum (x) { return 2 * x; }
function squareNum (x) { return x * x; }
var squareArgs = _.mapArgsWith(squareNum);
var squareThenDouble = squareArgs(doubleNum);
squareThenDouble(3);
// => 18
Signature: _.methodize(func:Function)
Takes a function and pulls the first argument out of the argument list and into
this
position. The returned function calls the original with its receiver
(this
) prepending the argument list. The original is called with a receiver
of null
.
function describe (obj) {
return obj.name + ": " + obj.description;
}
var democritus = {
name: "Democritus",
description: "originator of the atomic hypothesis",
describe: _.methodize(describe)
};
democritus.describe();
// => "Democritus: originator of the atomic hypothesis"
Signature: _.pipeline(func:Function[, func2:Function...])
or _.pipeline(funcArr:Array)
Aliases: _.t
Takes a list of functions, either as an array or as individual arguments and returns a function that takes some value as its first argument and runs it through a pipeline of the original functions given.
function halveNum (x) { return x / 2; };
function squareNum (x) { return x * x; };
function doubleNum (x) { return 2 * x; };
var halveSquareDouble = _.pipeline(halveNum, squareNum, doubleNum);
halveSquareDouble(1);
// => 0.5
var doubleSquareHalve = _.pipeline([doubleNum, squareNum, halveNum]);
doubleSquareHalve(1);
// => 2
Signature: _.splat(fun:Function)
Takes a function expecting one or more arguments and returns a function that takes an array and uses its elements as the arguments to the original function. This roughly corresponds to the spread operator in ECMAScript 6.
function listTwoNames (a, b) {
return a.name + " & " + b.name;
}
var listTwoNamesFromArray = _.splat(listTwoNames);
listTwoNamesFromArray([{ name: "Zeno" }, { name: "Parmenides"}]);
// => "Zeno & Parmenides"
Signature: _.unsplat(fun:Function)
Aliases: _.unsplatr
Takes a function expecting an array as its last argument and returns a function which works identically, but takes a list of trailing arguments instead. Roughly corresponds to rest parameters in ECMAScript 6.
function joinWith (joiner, arr) {
return arr.join(joiner);
}
var joinArgsWith = _.unsplat(joinWith);
joinArgsWith(" & ", "Plutarch", "Proclus");
// => "Plutarch & Proclus"
Signature: _.unsplatl(fun:Function)
Similar to unsplat, but takes a function expecting an array as its first argument and returns a function which works identically, but takes a list of leading arguments instead. Roughly corresponds to rest parameters in ECMAScript 6.
function joinWith (arr, joiner) {
return arr.join(joiner);
}
var joinArgsWith = _.unsplat(joinWith);
joinArgsWith("Olympiodorus", "Syrianus", " & ");
// => "Olympiodorus & Syrianus"
Functions to iterate over collections.
Signature: _.iterators.accumulate(iter:Function, binaryFn:Function, initial:Any)
Returns a function that when called will iterate one step with iter
and return
the value currently accumulated by using binaryFn
. The function will return undefined
once all values have been iterated over.
var generalsIterator = _.iterators.List(["Hannibal", "Scipio"]);
function countLetters(memo, element) {
return memo + element.length;
}
var generalsAcc = _.iterators.accumulate(generalsIterator, countLetters, 0);
generalsAcc();
// => 8
generalsAcc();
// => 14
generalsAcc();
// => undefined
Signature: _.iterators.accumulateWithReturn(iter:Function, binaryFn:Function, initial:Any)
Acts similarly to accumulate, except that binaryFn
is expected to return an
array of two elements. The value of the first element is given to the next run
of binaryFn
. The value of the second element is yielded by the iterator.
var fiveIter = _.iterators.List([1, 2, 3, 4, 5]);
function adderWithMessage (state, element) {
return [state + element, 'Total is ' + (state + element)];
}
var i = _.iterators.accumulateWithReturn(fiveIter, adderWithMessage, 0);
i();
// => "Total is 1"
i();
// => "Total is 3"
i();
// => "Total is 6"
Signature: _.iterators.drop(iter:Function[, numberToDrop:Number])
Given an iterator function iter
, will return a new iterator which iterates
over the same values as iter
, except that the first numberToDrop
values
will be omitted. If numberToDrop
is not provided, it will default to 1
.
var deityIter = _.iterators.List(["Zeus", "Apollo", "Athena", "Aphrodite"]);
var goddessIter = _.iterators.drop(deityIter, 2);
goddessIter();
// => "Athena"
goddessIter();
// => "Aphrodite"
Signature: _.iterators.foldl(iter:Function, binaryFn:Function[, seed:Any])
Aliases: iterators.reduce
Boils down the values given by iter
into a single value. The seed
is the
initial state. The binaryFn
is given two arguments: the seed
and the
current value yielded by iter
.
var sybylIter = _.iterators.List(["cumaean", "tiburtine"]);
function commaString (a, b) { return a + ", " + b; }
_.iterators.foldl(sybylIter, commaString);
// => "cumaean, tiburtine"
Signature: _.iterators.K(value:Any)
Aliases: iterators.constant
Returns a function that when invoked will always return value
.
var ceasar = _.iterators.K("Ceasar");
ceasar();
// => "ceasar"
Signature: _.iterators.List(array:Array)
Returns an iterater that when invoked will iterate over the contents of array
.
var triumvirIter = _.iterators.List(["Ceasar", "Pompey", "Crassus"];
triumvirIter();
// => "Ceasar"
triumvirIter();
// => "Pompey"
triumvirIter();
// => "Crassus"
Signature: _.iterators.map(iter:Function, unaryFn:Function)
Returns a new iterator function which on each iteration will return the result
of running iter
's current value through unaryFn
.
var notablesIter = _.iterators.List(["Socrates", "Plato"]);
function postfixAthenian (val) {
return val + ", Athenian";
}
var notableAtheniansIter = _.iterators.map(notablesIter, postfixAthenian);
notableAtheniansIter();
// => "Socrates, Athenian"
notableAtheniansIter();
// => "Plato, Athenian"
Signature: _.iterators.mapcat(iter:Function, unaryFn:Function)
Returns an iterator which is the result of flattening the contents of iter
,
and mapping the results with unaryFn
.
function naturalSmallerThan (x) {
return _.iterators.List(_.range(0, x));
}
var treeIter = _.iterators.Tree([1, [2]]);
var smallerThanIter = _.iterators.mapcat(treeIter, naturalSmallerThan);
smallerThanIter();
// => 0
smallerThanIter();
// => 0
smallerThanIter();
// => 1
Signature: _.iterators.numbers([start:Number])
Returns an iterator of integers which will begin with start
and increment by
one for each invocation. If start
is not provided it will default to 1
.
var twoAndUp = _.iterators.numbers(2);
twoAndUp();
// => 2
twoAndUp();
// => 3
twoAndUp();
// => 4
Signature: `_.iterators.range([from:Number, to:Number, by:Number]);
Returns an iterator whose values consist of numbers beginning with from
, ending with to
, in steps of size by
.
var by5 = _.iterators.range(5, Infinity, 5);
by5();
// => 5
by5();
// => 10
by5();
// => 15
Signature: _.iterators.reject(iter:Function, unaryPredicatFn:Function)
Returns an iterator consisting of the values of iter
which are not flagged
true
by unaryPredicateFn
.
var philosophers = ["Anaximander", "Socrates", "Heraclitus"];
var philosophersIter = _.iterators.List(philosophers);
function isSocrates (val) {
return val === "Socrates";
}
var preSocraticsIter = _.iterators.reject(philosophersIter, isSocrates);
preSocraticsIter()
// => "Anaximander"
preSocraticsIter()
// => "Heraclitus"
Signature: _.iterators.select(iter:Function, unaryPredicatFn:Function)
Aliases: iterators.find
, iteraters.filter
Returns an iterator consisting of the values of iter
which are flagged
true
by unaryPredicateFn
.
var philosophers = ["Anaximander", "Socrates", "Heraclitus"];
var philosophersIter = _.iterators.List(philosophers);
function isSocrates (val) {
return val === "Socrates";
}
var socraticIter = _.iterators.select(philosophersIter, isSocrates);
socraticIter()
// => "Socrates"
Signature: _.iterators.slice(iter:Function, numberToDrop:Number, numberToTake:Number)
Returns an iterator whose values consist of iter
's after removing
numberToDrop
from the head, and a maxiumum of numberToTake
of the remaining.
If numberToTake
is not specified, all of iter
's remaining values will be
used.
var emperors = ["Augustus", "Tiberius", "Caligula", "Claudius"];
var emperorsIter = _.iterators.List(emperors);
var middleEmperorsIter = _.iterators.slice(emperorsIter, 1, 2);
middleEmperorsIter();
// => "Tiberius"
middleEmperorsIter();
// => "Caligula"
middleEmperorsIter();
// => undefined
Signature: _.iterators.take(iter:Function[, numberToTake:Number])
Returns an iterator consisting of the first numberToTake
values yielded by
iter
. If numberToTake
is not provided, it will default to 1
.
var byzantineEmperors = ["Constantine", "Constantius", "Constans"];
var byzantineEmperorsIter = _.iterators.List(byzantineEmperors);
var firstTwoEmperorsIter = _.iterators.take(byzantineEmperorsIter, 2);
firstTwoEmperorsIter();
// => "Constantine"
firstTwoEmperorsIter();
// => "Constantius"
firstTwoEmperorsIter();
// => undefined
Signature: _.iterators.Tree(array:Array);
Returns an iterator that yields the individual values of a tree array
.
var rulers = ["Augustus", ["Constantine"], ["Leo", ["Charlemagne"]]];
var rulersIter = _.iterators.Tree(rulers);
rulersIter();
// => "Augustus"
rulersIter();
// => "Constantine"
rulersIter();
// => "Leo"
rulersIter();
// => "Charlemagne"
Signature: _.iterators.unfold(seed:Any, unaryFn:Function)
function greatify (val) {
return val + " the Great";
}
var greatIter = _.iterators.unfold("Constantine", greatify);
greatIter();
// => "Constantine the Great"
greatIter();
// => "Constantine the Great the Great"
greatIter();
// => "Constantine the Great the Great the Great"
Signature: _.iterators.unfold(seed:Any, unaryFn:Function)
Acts similarly to unfold, except that unaryFn
is expected to return an array
with two elements. The value of the first element is given to the next run of
unaryFn
. The value of the second element is yielded by the iterator.
var i = _.iterators.unfoldWithReturn(1, function(n) {
return [n + 1, n * n];
});
i();
// => 1
i();
// => 4
i();
// => 9
Functions which return whether the input meets a condition.
Signature: isAssociative(value:Any)
Returns a boolean indicating whether or not the value is an associative object.
An associative object is one where its elements can be accessed via a key or
index (e.g. arrays, arguments
, objects).
_.isAssociative(["Athens", "Sparta"]);
// => true
_.isAssociative(42);
// => false
Signature: _.isDecreasing(values:Any...)
Checks whether the arguments are monotonically decreasing values (i.e. whether each argument is less than the previous argument.)
_.isDecreasing(3, 2, 1);
// => true
_.isDecreasing(15, 12, 2);
// => true
_.isDecreasing(2, 3);
// => false
Signature: _.isEven(value:Any)
Checks whether the value is an even number.
_.isEven(12);
// => true
_.isEven(3);
// => false
_.isEven({});
// => false
Signature: _.isFloat(value:Any)
Checks whether the value is a "float." For the purposes of this function, a float
is a numeric value that is not an integer. A numeric value may be a number, a
string containing a number, a Number
object, etc.
NOTE: JavaScript itself makes no distinction between integers and floats. For
the purposes of this function both 1
and 1.0
are considered integers.
_.isFloat(1.1);
// => true
_.isFloat(1);
// => false
_.isFloat(1.0);
// => false
_.isFloat("2.15");
// => true
Signature: _.isIncreasing(value:Any...)
Checks whether the arguments are monotonically increasing values (i.e. each argument is greater than the previous argument.)
_.isIncreasing(1, 12, 15);
// => true
_.isIncreasing(1);
// => true
_.isIncreasing(5, 4);
// => false
Signature: _.isIndexed(value:Any)
Checks whether the value is "indexed." An indexed value is one which accepts a numerical index to access its elements. (e.g. arrays and strings)
NOTE: Underscore does not support cross-browser consistent use of strings as array-like values, so be wary in IE 8 when using string objects and in IE7 and earlier when using string literals & objects.
_.isIndexed("Socrates");
// => true
_.isIndexed({poison: "hemlock"});
// => false
Signature: _.isInstanceOf(value:Any, constructor:Function)
Checks whether the value is an instance of the constructor.
_.isInstanceOf(new Date(), Date);
// => true
_.isInstanceOf("Hippocrates", RegExp);
// => false
Signature: _.isInteger(value:Any)
Checks whether the value is a numeric integer. A numeric value can be a string
containing a number, a Number
object, etc.
_.isInteger(18);
// => true
_.isInteger("18");
// => true
_.isInteger(2.5);
// => false
_.isInteger(-1);
// => true
Signature: _.isJSON(value:Any)
Checks whether the value is valid JSON. See the spec for more information on what constitutes valid JSON.
NOTE: This function relies on JSON.parse
which is not available in IE7 and
earlier.
_.isJSON('{ "name": "Crockford" }');
// => true
_.isJSON({ name: "Crocket" });
// => false
Signature: _.isNegative(value:Any)
Checks whether the value is a negative number.
_.isNegative(-2);
// => true
_.isNegative(5);
// => false
Signature: _.isNumeric(value:Any)
A numeric is something that contains a numeric value, regardless of its type. It
can be a string containing a numeric value, exponential notation, a Number
object, etc.
_.isNumeric("14");
// => true
_.isNumeric("fourteen");
// => false
Signature: _.isOdd(value:Any)
Checks whether the value is an odd number.
_.isOdd(3);
// => true
_.isOdd(2);
// => false
_.isOdd({});
// => false
Signature: _.isPlainObject(value:Any);
Checks whether the value is a "plain" object created as an object literal ({}
)
or explicitly constructed with new Object()
. Instances of other constructors
are not plain objects.
_.isPlainObject({});
// => true
_.isPlainObject(new Date());
// => false
_.isPlainObject([]);
// => false
Signature: _.isPositive(value:Any)
Checks whether the value is a positive number.
_.isPositive(21);
// => true
_.isPositive(-3);
// => false
Signature: _.isSequential(value:Any)
Checks whether the value is a sequential composite type (i.e. arrays and
arguments
).
_.isSequential(["Herodotus", "Thucidydes");
// => true
_.isSequential(new Date);
// => false
Signature: _.isValidDate(value:Any)
Checks whether the value is a valid date. That is, the value is both an instance
of Date
and it represents an actual date.
Warning: This function does not verify
whether the original input to Date
is a real date. For instance,
new Date("02/30/2014")
is considered a valid date because Date
coerces that
into a representation of 03/02/2014. To validate strings representing a date,
consider using a date/time library like Moment.js.
_.isValidDate(new Date("January 1, 1900"));
// => true
_.isValidDate(new Date("The Last Great Time War"));
// => false
Signature: _.isZero(value:Any)
Checks whether the value is 0
.
_.isZero(0);
// => true
_.isZero("Pythagoras");
// => false
Functions to build objects.
Signature: _.frequencies(arr:Array)
Returns an object whose property keys are the values of arr
's elements. The
property values are a count of how many times that value appeared in arr
.
var citations = ["Plato", "Aristotle", "Plotinus", "Plato"];
_.frequencies(citations);
// => { Plato: 2, Aristotle: 1, Plotinus: 1 }
Signature: _.merge(obj1:Object[, obj:Object...])
Merges two or more objects starting with the left-most and applying the keys rightward.
_.merge({ a: "alpha" }, { b: "beta" });
// => { a: "alpha", b: "beta" }
Signature: _.renameKeys(obj:Object, keyMap:Object)
Takes an object (obj
) and a map of keys (keyMap
) and returns a new object
where the keys of obj
have been renamed as specified in keyMap
.
_.renameKeys({ a: 1, b: 2 }, { a: "alpha", b: "beta" });
// => { alpha: 1, beta: 2 }
Signature: _.setPath(obj:Object, value:Any, ks:Array, defaultValue:Any)
Sets the value of a property at any depth in obj
based on the path described
by the ks
array. If any of the properties in the ks
path don't exist, they
will be created with defaultValue
.
_.setPath({}, "Plotinus", ["Platonism", "Neoplatonism"], {});
// => { Platonism: { Neoplatonism: "Plotinus" } }
Signature: _.snapshot(obj:Object)
Snapshots/clones an object deeply.
var schools = { plato: "Academy", aristotle: "Lyceum" };
_.snapshot(schools);
// => { plato: "Academy", aristotle: "Lyceum" }
schools === _.snapshot(schools);
// => false
Signature: _.updatePath(obj:Object, fun:Function, ks:Array, defaultValue:Any)
Updates the value at any depth in a nested object based on the path described by
the ks
array. The function fun
is called with the current value and is
expected to return a replacement value. If no keys are provided, then the
object itself is presented to fun
. If a property in the path is missing, then
it will be created with defaultValue
.
var imperialize = function (val) {
if (val == "Republic) return "Empire";
else return val;
};
_.updatePath({ rome: "Republic" }, imperialize, ["rome"]);
// => { rome: "Empire" }
Functions to select values from an object.
Signature: _.accessor(field:String)
Returns a function that will attempt to look up a named field in any object that it is given.
var getName = _.accessor('name');
getName({ name: 'Seneca' });
// => 'Seneca'
Signature: _.dictionary(obj:Object)
Given an object, returns a function that will attempt to look up a field that it is given.
var generals = {
rome: "Scipio",
carthage: "Hannibal"
};
var getGeneralOf = _.dictionary(generals);
_.getGeneralOf("rome");
// => "Scipio"
Signature: _.getPath(obj:Object, ks:String|Array)
Gets the value at any depth in a nested object based on the path described by
the keys given. Keys may be given as an array or as a dot-separated string.
Returns undefined
if the path cannot be reached.
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined
Signature: _.hasPath(obj:Object, ks:String|Array)
Returns a boolean indicating whether there is a property at the path described by the keys given. Keys may be given as an array or as a dot-separated string.
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.hasPath(countries, "greece.athens.playwright");
// => true
_.hasPath(countries, "greece.sparta.playwright");
// => false
_.hasPath(countries, ["greece", "athens", "playwright"]);
// => true
_.hasPath(countries, ["greece", "sparta", "playwright"]);
// => false
Signature: _.kv(obj:Object, key:String)
Returns the key/value pair for a given property in an object, undefined if not found.
var playAuthor = {
"Medea": "Aeschylus"
};
_.kv(playAuthor, "Medea");
// => ["Medea", "Aeschylus"]
_.kv(playAuthor, "Hamlet");
// => undefined
Signature: _.omitWhen(obj, pred:Function)
Returns a copy of obj
omitting any properties that the predicate (pred
)
function returns true
for. The predicat function is invoked with each
property value, like so: pred(propValue)
.
var playwrights = {
euripedes: "Greece",
shakespere: "England"
};
_.omitWhen(obj, function (country) { return country == "England" });
// => { euripedes: "Greece" }
Signature: _.pickWhen(obj:Object, pred:Function)
Returns a copy of obj
containing only properties that the predicate (pred
)
function returns true
for. The predicate function is invoked with each
property value, like so: pred(propValue)
.
var playwrights = {
euripedes: "Greece",
shakespere: "England"
};
_.pickWhen(obj, function (country) { return country == "England" });
// => { shakespeare: "England" }
Signature: `_.selectKeys(obj:Object, ks:Array);
Returns a copy of obj
containing only the properties listed in the ks
array.
var philosopherCities = {
Philo: "Alexandria",
Plato: "Athens",
Plotinus: "Rome"
}
_.selectKeys(philosopherCities, ["Plato", "Plotinus"]);
// => { Plato: "Athens", Plotinus: "Rome" }
Functions which deal with whether a value "exists."
Signature: _.exists(value:Any)
Checks whether or not the value is "existy." Both null
and undefined
are
considered non-existy values. All other values are existy.
_.exists(null);
// => false
_.exists(undefined);
// => false
_.exists({});
// = > true
_.exists("Sparta");
// => true
Signature: _.falsey(value:Any)
Checks whether the value is falsey. A falsey value is one which coerces to
false
in a boolean context.
_.falsey(0);
// => true
_.falsey("");
// => true
_.falsey({});
// => false
_.falsey("Corinth");
// => false
Signature: _.firstExisting(value:Any[, value:Any...])
Returns the first existy argument from the argument list.
_.firstExisting("Socrates", "Plato");
// => "Socrates"
_.firstExisting(null, undefined, "Heraclitus");
// => "Heraclitus"
Signature: _.not(value:Any)
Returns a boolean which is the opposite of the truthiness of the original value.
_.not(0);
// => true
_.not(1);
// => false
_.not(true);
// => false
_.not(false);
// => true
_.not({});
// => false
_.not(null);
// => true
Signature: _.truthy(value:Any)
Checks whether the value is truthy. A truthy value is one which coerces to
true
in a boolean context.
_.truthy({});
// => true
_.truthy("Athens");
// => true
_.truthy(0);
// => false
_.truthy("");
// => false
Functions which wrap JavaScript's operators.
Signature: _.add(value:Number, value:Number[, value:Number...])
Returns the sum of the arguments.
_.add(1, 2, 3, 4);
// => 10
Signature: _.bitwiseAnd(value:Any, value:Any[, value:Any...])
Returns the result of using the &
operator on the arguments.
_.bitwiseAnd(1, 3);
// => 1
_.bitwiseAnd(1, 3, 2);
// => 0
Signature: _.bitwiseLeft(value:Any, value:Any[, value:Any...])
Returns the result of using the <<
operator on the arguments.
_.bitwiseLeft(1, 3);
// => 8
_.bitwiseLeft(1, 3, 2);
// => 32
Signature: _.bitwiseRight(value:Any, value:Any[, value:Any...])
Returns the result of using the >>
operator on the arguments.
_.bitwiseRight(3, 1);
// => 1
_.bitwiseRight(3, 1, 3);
// => 0
Signature: _.bitwiseNot(value:Any)
Returns the result of using the ~
operator on the value.
_.bitwiseNot(1);
// => -2
_.bitwiseOr(2);
// => -3
Signature: _.bitwiseOr(value:Any, value:Any[, value:Any...])
Returns the result of using the |
operator on the arguments.
_.bitwiseOr(1, 3);
// => 3
_.bitwiseOr(1, 3, 4);
// => 7
Signature: _.bitwiseXor(value:Any, value:Any[, value:Any...])
Returns the result of using the ^
operator on the arguments.
_.bitwiseXor(1, 3);
// => 2
_.bitwiseXor(1, 3, 3);
// => 1
Signature: _.bitwiseZ(value:Any, value:Any[, value:Any...])
Returns the result of using the >>>
operator on the arguments.
_.bitwiseZ(72, 32);
// => 72
_.bitwiseZ(72, 32, 2);
// => 18
Signature: _.dec(value:Number)
Returns the result of decrementing the value by 1
.
_.dec(2);
// => 1
Signature: _.div(value:Number, value:Number[, value:Number...])
Returns the quotient of the arguments.
_.div(8, 2);
// => 4
_.div(8, 2, 2);
// => 2
Signature: _.eq(value:Any, value:Any[, value:Any...])
Compares the arguments with loose equality (==
).
_.eq(1, "1");
// => true
_.eq(1, 15);
// => false
_.eq(1, true, "1");
// => true
_.eq(1, 1, 15);
// => false
Signature: _.gt(value:Any, value:Any[, value:Any...])
Checks whether each argument is greater than the previous argument.
_.gt(1, 2);
// => true
_.gt(1, 2, 3);
// => true
_.gt(1, 6, 2);
// => false
Signature: _.gte(value:Any, value:Any[, value:Any...])
Checks whether each argument is greater than or equal to the previous argument.
_.gte(1, 2);
// => true
_.gte(1, 1, 3);
// => true
_.gte(1, 6, 2);
// => false
Signature: _.inc(value:Number)
Returns the result of incrementing the value by 1
.
_.inc(2);
// => 3
Signature: _.lt(value:Any, value:Any[, value:Any...])
Checks whether each argument is less than the previous argument.
_.lt(2, 1);
// => true
_.lt(2, 1, 0);
// => true
_.lt(2, 1, 12);
// => false
Signature: _.lte(value:Any, value:Any[, value:Any...])
Checks whether each argument is less than or equal to the previous argument.
_.lte(2, 1);
// => true
_.lte(2, 1, 1);
// => true
_.lte(2, 1, 12);
// => false
Signature: _.mul(value:Number, value:Number[, value:Number...])
Returns the product of the arguments.
_.mul(1, 2, 3, 4);
// => 24
Signature: _.mod(dividend:Number, divisor:Number)
Returns the remainder of dividing dividend
by divisor
.
_.mod(26, 5);
// => 1
_.mod(14, 3);
// => 2
Signature: _.neg(num:Number)
Returns a new number with the opposite sign value of num
.
_.neg(5);
// => -5
_.neg(-3);
// => 3
Signature: _.neq(value:Any, value:Any[, value:Any...])
Checks whether each argument is not equal to the previous argument, using loose
inequality (!=
).
_.neq(2, 1);
// => true
_.neq(2, 1, 1);
// => true
_.neq(1, 1);
// => false
Signature: _.not(value:Any)
Returns a boolean which is the opposite of the truthiness of the original value.
_.not(0);
// => true
_.not(1);
// => false
_.not(true);
// => false
_.not(false);
// => true
_.not({});
// => false
_.not(null);
// => true
Signature: _.seq(value:Any, value:Any[, value:Any...])
Checks whether the arguments are strictly equal (===
) to each other.
_.seq(2, 2);
// => true
_.seq(2, "2");
// => false
_.seq(2, 2, 2);
// => true
Signature: _.sneq(value:Any, value:Any[, value:Any...])
Checks whether the arguments are strictly not equal (!==
) to each other.
_.sneq(2, 2);
// => false
_.sneq(2, "2");
// => true
_.sneq(2, 2, 2);
// => false
Signature: _.sub(value:Number, value:Number[, value:Number...])
Returns the difference of the arguments.
_.sub(10, 3);
// => 7
_.sub(10, 3, 5);
// => 2
Functions for working with strings.
Signature: _.camelCase(string:String)
Converts a dash-separated string to camel case. Opposite of toDash.
_.camelCase("ancient-greece");
// => "ancientGreece"
Signature: _.explode(s:String)
Explodes a string into an array of characters. Opposite of implode.
_.explode("Plato");
// => ["P", "l", "a", "t", "o"]
Signature: _.fromQuery(str:String)
Takes a URL query string and converts it into an equivalent JavaScript object. Opposite of toQuery
_.fromQuery("forms%5Bperfect%5D=circle&forms%5Bimperfect%5D=square");
// => { forms: { perfect: "circle", imperfect: "square" } }
Signature: _.implode(a:Array)
Implodes an array of strings into a single string. Opposite of explode.
_.implode(["H", "o", "m", "e", "r"]);
// => "Homer"
Signature: _.strContains(str:String, search:String)
Reports whether a string contains a search string.
_.strContains("Acropolis", "polis");
// => true
Signature: _.toDash(string:String)
Converts a camel case string to a dashed string. Opposite of camelCase.
_.toDash("thisIsSparta");
// => "this-is-sparta"
Signature: _.toQuery(obj:Object)
Takes an object and converts it into an equivalent URL query string. Opposite of fromQuery.
_.toQuery({ forms: { perfect: "circle", imperfect: "square" } });
// => "forms%5Bperfect%5D=circle&forms%5Bimperfect%5D=square"
Trampoline functions.
Documentation should use Journo formats and standards.
done: function(value) {
trampoline: function(fun /*, args */) {
partition
and partitionAll
to chunk
and chunkAll
to avoid name conflicts with Underscore's partition
- #115toQuery
and fromQuery
- #134always
to an alias of Underscore's constant
. - #132