Underscore.js 1.1.7
(c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
Underscore is freely distributable under the MIT license.
Portions of Underscore are inspired or borrowed from Prototype,
@@ -26,17 +26,16 @@
global object.
The cornerstone, an each implementation, aka forEach.
+Handles objects with the built-in forEach, arrays, and raw objects.
Delegates to ECMAScript 5's native forEach if available.
Get the first element of an array. Passing n will return the first N
values in the array. Aliased as head. The guard check allows it to work
with _.map.
Returns everything but the first entry of the array. Aliased as tail.
Especially useful on the arguments object. Passing an index will return
the rest of the values in the array from that index onward. The guard
check allows it to work with _.map.
Produce a duplicate-free version of the array. If the array has already
been sorted, you have the option of using a faster algorithm.
Aliased as unique.
If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
we need this function. Return the position of the first occurrence of an
item in an array, or -1 if the item is not included in the array.
Delegates to ECMAScript 5's native indexOf if available.
@@ -246,13 +257,13 @@
if(nativeIndexOf&&array.indexOf===nativeIndexOf)returnarray.indexOf(item);for(i=0,l=array.length;i<l;i++)if(array[i]===item)returni;return-1;
- };
Create a function bound to a given object (assigning this, and arguments,
optionally). Binding with arguments is also known as curry.
Delegates to ECMAScript 5's native Function.bind if available.
We check for func.bind first, to fail fast when func is undefined.
Returns a function, that, as long as it continues to be invoked, will not
be triggered. The function will be called after it stops being called for
N milliseconds.
Returns the first function passed as an argument to the second,
allowing you to adjust arguments, run code before and after, and
conditionally execute the original function.
Invokes interceptor with the obj, and then returns obj.
The primary purpose of this method is to "tap into" a method chain, in
order to perform operations on intermediate results within the chain.
JavaScript micro-templating, similar to John Resig's implementation.
Underscore templating handles arbitrary delimiters, preserves whitespace,
and correctly escapes quotes within interpolated code.
If Underscore is called as a function, it returns a wrapped object that
can be used OO-style. This wrapper holds altered versions of all the
-underscore functions. Wrapped objects may be chained.
- all_.all(list, [iterator], [context])
+ all_.all(list, iterator, [context])Alias: every
Returns true if all of the values in the list pass the iterator
- truth test. If an iterator is not provided, the truthy value of
- the element will be used instead. Delegates to the native method every, if
- present.
+ truth test. Delegates to the native method every, if present.
pluck_.pluck(list, propertyName)
- An convenient version of what is perhaps the most common use-case for
+ A convenient version of what is perhaps the most common use-case for
map: extracting a list of property values.
@@ -433,12 +432,23 @@
Collection Functions (Arrays or Objects)
sortBy_.sortBy(list, iterator, [context])
- Returns a sorted list, ranked by the results of running each
- value through iterator.
+ Returns a sorted copy of list, ranked by the results of running
+ each value through iterator.
+ union_.union(*arrays)
- Produces a duplicate-free version of the array, using === to test
- object equality. If you know in advance that the array is sorted,
- passing true for isSorted will run a much faster algorithm.
+ Computes the union of the passed-in arrays: the list of unique items,
+ in order, that are present in one or more of the arrays.
+ intersection_.intersection(*arrays)
Computes the list of values that are the intersection of all the arrays.
Each value in the result is present in each of the arrays.
+ uniq_.uniq(array, [isSorted])
+ Alias: unique
+
+ Produces a duplicate-free version of the array, using === to test
+ object equality. If you know in advance that the array is sorted,
+ passing true for isSorted will run a much faster algorithm.
+
+
+_.uniq([1, 2, 1, 3, 1, 4]);
+=> [1, 2, 3, 4]
@@ -1236,6 +1268,11 @@
Links & Suggested Reading
Functional JavaScript,
which includes comprehensive higher-order function support as well as string lambdas.
+
+
+ Michael Aufreiter's Data.js,
+ a data manipulation + persistence library for JavaScript.
+
+ 1.1.7 — July 13, 2011
+ Added _.groupBy, which aggregates a collection into groups of like items.
+ Added _.untion and _.difference, to complement the
+ (re-named) _.intersection.
+ Various improvements for support of sparse arrays.
+ _.toArray now returns a clone, if directly passed an array.
+ _.functions now also returns the names of functions that are present
+ in the prototype chain.
+
+
1.1.6 — April 18, 2011
Added _.after, which will return a function that only runs after
diff --git a/package.json b/package.json
index 86c918592..08396c4d9 100644
--- a/package.json
+++ b/package.json
@@ -8,5 +8,5 @@
"dependencies" : [],
"repository" : {"type": "git", "url": "git://github.com/documentcloud/underscore.git"},
"main" : "underscore.js",
- "version" : "1.1.6"
+ "version" : "1.1.7"
}
diff --git a/test/arrays.js b/test/arrays.js
index e031afe9b..32dd73a55 100644
--- a/test/arrays.js
+++ b/test/arrays.js
@@ -65,14 +65,24 @@ $(document).ready(function() {
equals(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
});
- test("arrays: intersect", function() {
+ test("arrays: intersection", function() {
var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho'];
- equals(_.intersect(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
- equals(_(stooges).intersect(leaders).join(''), 'moe', 'can perform an OO-style intersection');
- var result = (function(){ return _.intersect(arguments, leaders); })('moe', 'curly', 'larry');
+ equals(_.intersection(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
+ equals(_(stooges).intersection(leaders).join(''), 'moe', 'can perform an OO-style intersection');
+ var result = (function(){ return _.intersection(arguments, leaders); })('moe', 'curly', 'larry');
equals(result.join(''), 'moe', 'works on an arguments object');
});
+ test("arrays: union", function() {
+ var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]);
+ equals(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays');
+ });
+
+ test("arrays: difference", function() {
+ var result = _.difference([1, 2, 3], [2, 30, 40]);
+ equals(result.join(' '), '1 3', 'takes the difference of two arrays');
+ });
+
test('arrays: zip', function() {
var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];
var stooges = _.zip(names, ages, leaders);
diff --git a/test/collections.js b/test/collections.js
index ff365f8ea..005ee169e 100644
--- a/test/collections.js
+++ b/test/collections.js
@@ -26,10 +26,6 @@ $(document).ready(function() {
_.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; });
ok(answer, 'can reference the original collection from inside the iterator');
- answers = [];
- _.each({range : 1, speed : 2, length : 3}, function(v){ answers.push(v); });
- ok(answers.join(', '), '1, 2, 3', 'can iterate over objects with numeric length properties');
-
answers = 0;
_.each(null, function(){ ++answers; });
equals(answers, 0, 'handles a null properly');
@@ -45,7 +41,7 @@ $(document).ready(function() {
var doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
equals(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers');
- var ids = _.map(document.body.childNodes, function(n){ return n.id; });
+ var ids = _.map($('div.underscore-test').children(), function(n){ return n.id; });
ok(_.include(ids, 'qunit-header'), 'can use collection methods on NodeLists');
var ids = _.map(document.images, function(n){ return n.id; });
@@ -81,6 +77,13 @@ $(document).ready(function() {
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
+
+ // Sparse arrays:
+ var sparseArray = [];
+ sparseArray[100] = 10;
+ sparseArray[200] = 20;
+
+ equals(_.reduce(sparseArray, function(a, b){ return a + b }), 30, 'initially-sparse arrays with no memo');
});
test('collections: reduceRight', function() {
@@ -132,12 +135,15 @@ $(document).ready(function() {
});
test('collections: any', function() {
+ var nativeSome = Array.prototype.some;
+ Array.prototype.some = null;
ok(!_.any([]), 'the empty set');
ok(!_.any([false, false, false]), 'all false values');
ok(_.any([false, false, true]), 'one true value');
ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers');
ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number');
ok(_.some([false, false, true]), 'aliased as "some"');
+ Array.prototype.some = nativeSome;
});
test('collections: include', function() {
@@ -186,6 +192,12 @@ $(document).ready(function() {
equals(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
});
+ test('collections: groupBy', function() {
+ var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
+ ok('0' in parity && '1' in parity, 'created a group for each value');
+ equals(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
+ });
+
test('collections: sortedIndex', function() {
var numbers = [10, 20, 30, 40, 50], num = 35;
var index = _.sortedIndex(numbers, num);
@@ -195,6 +207,9 @@ $(document).ready(function() {
test('collections: toArray', function() {
ok(!_.isArray(arguments), 'arguments object is not an array');
ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array');
+ var a = [1,2,3];
+ ok(_.toArray(a) !== a, 'array is cloned');
+ equals(_.toArray(a).join(', '), '1, 2, 3', 'cloned array contains same elements');
var numbers = _.toArray({one : 1, two : 2, three : 3});
equals(numbers.join(', '), '1, 2, 3', 'object flattened into array');
diff --git a/test/functions.js b/test/functions.js
index 95267e73a..2a1bd51bd 100644
--- a/test/functions.js
+++ b/test/functions.js
@@ -73,8 +73,8 @@ $(document).ready(function() {
asyncTest("functions: delay", 2, function() {
var delayed = false;
_.delay(function(){ delayed = true; }, 100);
- _.delay(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
- _.delay(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
+ setTimeout(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
+ setTimeout(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
});
asyncTest("functions: defer", 1, function() {
diff --git a/test/objects.js b/test/objects.js
index 93c441176..78add1fed 100644
--- a/test/objects.js
+++ b/test/objects.js
@@ -22,6 +22,10 @@ $(document).ready(function() {
test("objects: functions", function() {
var obj = {a : 'dash', b : _.map, c : (/yo/), d : _.reduce};
ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object');
+
+ var Animal = function(){};
+ Animal.prototype.run = function(){};
+ equals(_.functions(new Animal).join(''), 'run', 'also looks up functions on the prototype');
});
test("objects: extend", function() {
@@ -77,6 +81,8 @@ $(document).ready(function() {
ok(_.isEqual(new Date(100), new Date(100)), 'identical dates are equal');
ok(_.isEqual((/hello/ig), (/hello/ig)), 'identical regexes are equal');
ok(!_.isEqual(null, [1]), 'a falsy is never equal to a truthy');
+ ok(_.isEqual({isEqual: function () { return true; }}, {}), 'first object implements `isEqual`');
+ ok(_.isEqual({}, {isEqual: function () { return true; }}), 'second object implements `isEqual`');
ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), 'objects with the same number of undefined keys are not equal');
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'wrapped objects are not equal');
equals(_({x: 1, y: 2}).chain().isEqual(_({x: 1, y: 2}).chain()).value(), true, 'wrapped objects are equal');
@@ -136,6 +142,21 @@ $(document).ready(function() {
ok(_.isArguments(iArguments), 'even from another frame');
});
+ test("objects: isObject", function() {
+ ok(_.isObject(arguments), 'the arguments object is object');
+ ok(_.isObject([1, 2, 3]), 'and arrays');
+ ok(_.isObject($('html')[0]), 'and DOM element');
+ ok(_.isObject(iElement), 'even from another frame');
+ ok(_.isObject(function () {}), 'and functions');
+ ok(_.isObject(iFunction), 'even from another frame');
+ ok(!_.isObject(null), 'but not null');
+ ok(!_.isObject(undefined), 'and not undefined');
+ ok(!_.isObject('string'), 'and not string');
+ ok(!_.isObject(12), 'and not number');
+ ok(!_.isObject(true), 'and not boolean');
+ ok(_.isObject(new String('string')), 'but new String()');
+ });
+
test("objects: isArray", function() {
ok(!_.isArray(arguments), 'the arguments object is not an array');
ok(_.isArray([1, 2, 3]), 'but arrays are');
diff --git a/test/test.html b/test/test.html
index c67acf596..f8609aa26 100644
--- a/test/test.html
+++ b/test/test.html
@@ -16,26 +16,27 @@
-
Underscore Test Suite
-
-
-
-
-
Underscore Speed Suite
-
- A representative sample of the functions are benchmarked here, to provide
- a sense of how fast they might run in different browsers.
- Each iteration runs on an array of 1000 elements.
- For example, the 'intersect' test measures the number of times you can
- find the intersection of two thousand-element arrays in one second.
-
-
+
+
Underscore Test Suite
+
+
+
+
+
Underscore Speed Suite
+
+ A representative sample of the functions are benchmarked here, to provide
+ a sense of how fast they might run in different browsers.
+ Each iteration runs on an array of 1000 elements.
+ For example, the 'intersect' test measures the number of times you can
+ find the intersection of two thousand-element arrays in one second.
+