JS.Enumerable
JS.Enumerable is essentially a straight port of Ruby’s Enumerable module to JavaScript. Some
of the methods have slightly different names in keeping with JavaScript conventions, but the
underlying idea is this: the module provides methods usable by any class that represents
collections or lists of things. The only stipulation is that your class must have a forEach
method that calls a given function with each member of the collection in turn, with an index
variable if desired.
Here’s a simple class that stores some of its instance data in a list, just so you get the idea:
var Collection = new JS.Class({
include: JS.Enumerable,
initialize: function() {
this.list = [];
for (var i = 0, n = arguments.length; i < n; i++)
this.list.push(arguments[i]);
},
forEach: function(block, context) {
for (var i = 0, n = this.list.length; i < n; i++)
block.call(context || null, this.list[i], i);
}
});
Let’s create an instance and see what it does:
var list = new Collection(3,7,4,8,2);
list.forEach(function(x, i) {
console.log(x, i);
});
// prints...
// 3 0
// 7 1
// 4 2
// 8 3
// 2 4
The API provided by the Enumerable module to the Collection class is as follows. In
the argument list of each method, block is a function and context is an optional
argument that sets the meaning of the keyword this inside block.
all(block, context)
Returns true iff block returns true for every member of the collection. Aliased as every().
new Collection(3,7,4,8,2).all(function(x) {
return x > 5;
})
// -> false
new Collection(3,7,4,8,2).all(function(x) {
return typeof x == 'number';
})
// -> true
any(block, context)
Returns true if block returns true for one or more members of the collection. Aliased as some().
new Collection(3,7,4,8,2).any(function(x) {
return x > 5;
})
// -> true
new Collection(3,7,4,8,2).any(function(x) {
return typeof x == 'object';
})
// -> false
collect(block, context)
Alias for map().
detect(block, context)
Alias for find().
entries()
Alias for toArray().
every(block, context)
Alias for all().
forEachCons(n, block, context)
Calls block with every set of n consecutive members of the collection.
new Collection(3,7,4,8,2).forEachCons(3, function(list) {
console.log(list);
});
// prints
// [3, 7, 4]
// [7, 4, 8]
// [4, 8, 2]
forEachSlice(n, block, context)
Splits the collection up into pieces of length n, and call block with each
piece in turn.
new Collection(3,7,4,8,2).forEachSlice(2, function(list) {
console.log(list);
});
// prints
// [3, 7]
// [4, 8]
// [2]
filter(block, context)
Alias for select().
find(block, context)
Returns the first member of the collection for which block returns true. Aliased as detect().
new Collection(3,7,4,8,2).find(function(x) {
return x > 5;
})
// -> 7
findAll(block, context)
Alias for select().
inject(memo, block, context)
Returns the result of reducing the collection down to a single value using a callback
function. The first time your block is called, it is passed the value of memo you
specified. The return value of block becomes the next value of memo.
// sum the values
new Collection(3,7,4,8,2).inject(0, function(memo, x) {
return memo + x;
})
// -> 24
map(block, context)
Returns an Array formed by calling block on each member of the collection. Aliased as collect().
// square the numbers
new Collection(3,7,4,8,2).map(function(x) {
return x * x;
})
// -> [9, 49, 16, 64, 4]
max(block, context)
Returns the member of the collection with the maximum value. Members must use Comparable
or be comparable using JavaScript’s standard comparison operators. If a block is passed,
it is used to sort the members. If no block is passed, a sensible default sort method
is used.
new Collection(3,7,4,8,2).max() // -> 8
new Collection(3,7,4,8,2).max(function(a,b) {
return (a%7) - (b%7);
})
// -> 4
member(needle)
Returns true iff the collection contains any members equal to needle. Items are checked for
equality (==) rather than identity (===).
new Collection(3,7,4,8,2).member('7') // -> true
new Collection(3,7,4,8,2).member('foo') // -> false
min(block, context)
Much like max(), except it returns the minimum value.
partition(block, context)
Returns two arrays, one containing members for which block returns true, the other
containing those for which it returns false.
new Collection(3,7,4,8,2).partition(function(x, i) {
return x > i;
})
// -> [ [3, 7, 4, 8], [2] ]
select(block, context)
Returns a new Array containing the members of the collection for which block returns true.
Aliased as filter() and findAll().
new Collection(3,7,4,8,2).select(function(x) {
return x > 5;
})
// -> [7, 8]
reject(block, context)
Returns a new Array containing the members of the collection for which block returns false.
new Collection(3,7,4,8,2).reject(function(x) {
return x > 5;
})
// -> [3, 4, 2]
some(block, context)
Alias for any().
sort(block, context)
Returns a new Array containing the members of the collection in sort order. The members
must either use Comparable or be comparable using JavaScript’s
standard comparison operators. If no block is passed, a sensible default sort method
is used, otherwise the block itself is used to perform sorting.
new Collection(3,7,4,8,2).sort()
// -> [2, 3, 4, 7, 8]
// sort by comparing values modulo 7
new Collection(3,7,4,8,2).sort(function(a,b) {
return (a%7) - (b%7);
})
// -> [7, 8, 2, 3, 4]
sortBy(block, context)
Returns a new Array containing the members of the collection sorted according to the
value that block returns for them.
// sort values modulo 7
new Collection(3,7,4,8,2).sortBy(function(x) {
return x % 7;
})
// -> [7, 8, 2, 3, 4]
toArray()
Returns a new Array containing the members of the collection. Aliased as entries().
zip(args, block, context)
This one is rather tricky to explain in words, so I’ll just let the Ruby docs explain:
Converts any arguments to arrays, then merges elements of collection with corresponding elements
from each argument. This generates a sequence of n-element arrays, where n is one
more that the count of arguments. If the size of any argument is less than the size of the
collection, null values are supplied. If a block is given, it is invoked for each output array,
otherwise an array of arrays is returned.
What this translates to in practise:
new Collection(3,7,4,8,2).zip([1,9,3,6,4], [6,3,3])
// -> [ [3,1,6], [7,9,3], [4,3,3],
// [8,6,null], [2,4,null] ]
new Collection(3,7,4,8,2).zip([1,9,3,6,4], function(list) {
console.log(list)
})
// prints...
// [3, 1]
// [7, 9]
// [4, 3]
// [8, 6]
// [2, 4]