From 86e6dd58c2817b40a1249e452cc915f3375e79a5 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Wed, 18 Nov 2009 16:11:35 -0500
Subject: [PATCH 1/5] code-ify stopIteration in the docs
---
index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/index.html b/index.html
index f0bc7a335..ff1a6dc9e 100644
--- a/index.html
+++ b/index.html
@@ -920,7 +920,7 @@ Change Log
- Started using the native StopIteration object in browsers that support it.
+ Started using the native StopIteration object in browsers that support it.
Fixed Underscore setup for CommonJS environments.
From 8cac2d5bd75c606fa987a97a97213e48974ed7f0 Mon Sep 17 00:00:00 2001
From: Luke Sutton
Date: Thu, 19 Nov 2009 11:07:14 +1030
Subject: [PATCH 2/5] Add init(), tail() and reverse() Array functions. Alias
first() to head();
---
test/arrays.js | 15 +++++++++++++++
underscore.js | 24 ++++++++++++++++++++++++
2 files changed, 39 insertions(+)
diff --git a/test/arrays.js b/test/arrays.js
index d069d9d62..a9dcb4e90 100644
--- a/test/arrays.js
+++ b/test/arrays.js
@@ -58,4 +58,19 @@ $(document).ready(function() {
equals(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
});
+ test("arrays: tail", function() {
+ var numbers = [1, 2, 3, 4];
+ equals(_.tail(numbers).join(", "), "2, 3, 4");
+ });
+
+ test("arrays: init", function() {
+ var numbers = [1, 2, 3, 4];
+ equals(_.init(numbers).join(", "), "1, 2, 3");
+ });
+
+ test("arrays: reverse", function() {
+ var numbers = [1, 2, 4, 6];
+ equals(_.reverse(numbers).join(", "), "6, 4, 2, 1");
+ });
+
});
diff --git a/underscore.js b/underscore.js
index ac1b8659d..ad6dbecac 100644
--- a/underscore.js
+++ b/underscore.js
@@ -305,6 +305,29 @@
while (i--) if (array[i] === item) return i;
return -1;
};
+
+ // Returns everything but the first entry of the array. Conceptually the
+ // same as calling shift(), but doesn't mutate the array passed in.
+ _.tail = function(array) {
+ var tail = _.clone(array);
+ tail.shift();
+ return tail;
+ };
+
+ // Returns everything but the last entry of the array. Conceptually the
+ // same as calling pop(), but doesn't mutate the array passed in.
+ _.init = function(array) {
+ var init = _.clone(array);
+ init.pop();
+ return init;
+ };
+
+ // Returns a new array, with the entries or the passed-in array in reverse
+ // order.
+ _.reverse = function(array) {
+ var reverse = _.clone(array);
+ return reverse.reverse();
+ };
/* ----------------------- Function Functions: -----------------------------*/
@@ -501,6 +524,7 @@
/*------------------------------- Aliases ----------------------------------*/
+ _.head = _.first;
_.forEach = _.each;
_.foldl = _.inject = _.reduce;
_.foldr = _.reduceRight;
From 4ed79d5f778e8e8eb5fa0232545ac719cf4c9d42 Mon Sep 17 00:00:00 2001
From: Luke Sutton
Date: Thu, 19 Nov 2009 11:35:21 +1030
Subject: [PATCH 3/5] Correct the test for functions() to account for the new
functions and aliases.
---
test/utility.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/test/utility.js b/test/utility.js
index ed6ee120b..0acc6a16d 100644
--- a/test/utility.js
+++ b/test/utility.js
@@ -31,13 +31,13 @@ $(document).ready(function() {
});
test("utility: functions", function() {
- var expected = ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact", "compose",
- "defer", "delay", "detect", "each", "every", "extend", "filter", "first",
- "flatten", "foldl", "foldr", "forEach", "functions", "identity", "include",
- "indexOf", "inject", "intersect", "invoke", "isArray", "isElement", "isEmpty", "isEqual",
+ var expected = ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact",
+ "compose","defer", "delay", "detect", "each", "every", "extend", "filter", "first",
+ "flatten", "foldl", "foldr", "forEach", "functions", "head", "identity", "include",
+ "indexOf", "init", "inject", "intersect", "invoke", "isArray", "isElement", "isEmpty", "isEqual",
"isFunction", "isNumber", "isString", "isUndefined", "keys", "last", "lastIndexOf", "map", "max",
- "methods", "min", "pluck", "reduce", "reduceRight", "reject", "select",
- "size", "some", "sortBy", "sortedIndex", "template", "toArray", "uniq",
+ "methods", "min", "pluck", "reduce", "reduceRight", "reject", "reverse", "select",
+ "size", "some", "sortBy", "sortedIndex", "tail", "template", "toArray", "uniq",
"uniqueId", "values", "without", "wrap", "zip"];
ok(_(expected).isEqual(_.methods()), 'provides a sorted list of functions');
});
From f8e939d30ac53ba672e0f94a20f680d2b6badcfa Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Wed, 18 Nov 2009 21:54:50 -0500
Subject: [PATCH 4/5] fixing template test validation for IE
---
test/utility.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/utility.js b/test/utility.js
index ed6ee120b..16cb01013 100644
--- a/test/utility.js
+++ b/test/utility.js
@@ -46,9 +46,9 @@ $(document).ready(function() {
var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");
var result = basicTemplate({thing : 'This'});
equals(result, "This is gettin' on my noives!", 'can do basic attribute interpolation');
- var fancyTemplate = _.template("<% for (key in people) { %><%= people[key] %><% } %>");
+ var fancyTemplate = _.template("<% for (key in people) { %>- <%= people[key] %>
<% } %>
");
result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
- equals(result, "MoeLarryCurly", 'can run arbitrary javascript in templates');
+ equals(result, "", 'can run arbitrary javascript in templates');
});
});
From ae968a6ea06dd4fd6f5184b3e6d14f9a077b3d01 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Date: Thu, 19 Nov 2009 09:37:56 -0500
Subject: [PATCH 5/5] Underscore 0.4.5, with first/rest, head/tail, and all
Array functions guaranteed to work on 'arguments' objects. Many method
implementations reworked to use _.rest()
---
index.html | 43 +++++++++++++++++++++++------
test/arrays.js | 69 ++++++++++++++++++++++++++++-------------------
test/utility.js | 6 ++---
underscore-min.js | 22 +++++++--------
underscore.js | 63 ++++++++++++++++---------------------------
5 files changed, 113 insertions(+), 90 deletions(-)
diff --git a/index.html b/index.html
index ff1a6dc9e..c2b1ac241 100644
--- a/index.html
+++ b/index.html
@@ -107,11 +107,11 @@ Downloads (Right-click, and u
@@ -183,7 +183,7 @@ Table of Contents
Arrays
- first, last,
+ first, rest, last,
compact, flatten, without, uniq,
intersect, zip, indexOf,
lastIndexOf
@@ -454,15 +454,33 @@
Collection Functions (Arrays or Objects)
Array Functions
+
+
+ Note: All array functions will also work on the arguments object.
+
- _.first(array)
+ _.first(array, [n])
+ Alias: head
- Convenience to return the first element of an array (identical to array[0]).
+ Returns the first element of an array. Passing n will
+ return the first n elements of the array.
-_.first([3, 2, 1]);
-=> 3
+_.first([5, 4, 3, 2, 1]);
+=> 5
+
+
+
+ _.rest(array, [index])
+ Alias: tail
+
+ Returns the rest of the elements in an array. Pass an index
+ to return the values of the array from that index onward.
+
+
+_.rest([5, 4, 3, 2, 1]);
+=> [4, 3, 2, 1]
@@ -471,7 +489,7 @@
Array Functions
Returns the last element of an array.
-_.last([3, 2, 1]);
+_.last([5, 4, 3, 2, 1]);
=> 1
@@ -912,6 +930,15 @@ Chaining
Change Log
+
+
+ Added rest for Arrays and arguments objects, and aliased
+ first as head, and rest as tail,
+ thanks to Luke Sutton's patches.
+ Added tests ensuring that all Underscore Array functions also work on
+ arguments objects.
+
+
Added isString, and isNumber, for consistency. Fixed
diff --git a/test/arrays.js b/test/arrays.js
index a9dcb4e90..5464756f6 100644
--- a/test/arrays.js
+++ b/test/arrays.js
@@ -1,76 +1,89 @@
$(document).ready(function() {
-
+
module("Array-only functions (last, compact, uniq, and so on...)");
-
+
test("arrays: first", function() {
equals(_.first([1,2,3]), 1, 'can pull out the first element of an array');
equals(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"');
+ equals(_.first([1,2,3], 2).join(', '), '1, 2', 'can pass an index to first');
+ var result = (function(){ return _.first(arguments); })(4, 3, 2, 1);
+ equals(result, 4, 'works on an arguments object.');
});
-
+
+ test("arrays: rest", function() {
+ var numbers = [1, 2, 3, 4];
+ equals(_.rest(numbers).join(", "), "2, 3, 4", 'working rest()');
+ equals(_.rest(numbers, 2).join(', '), '3, 4', 'rest can take an index');
+ var result = (function(){ return _(arguments).tail(); })(1, 2, 3, 4);
+ equals(result.join(', '), '2, 3, 4', 'aliased as tail and works on arguments object');
+ });
+
test("arrays: last", function() {
equals(_.last([1,2,3]), 3, 'can pull out the last element of an array');
+ var result = (function(){ return _(arguments).last(); })(1, 2, 3, 4);
+ equals(result, 4, 'works on an arguments object');
});
-
+
test("arrays: compact", function() {
equals(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values');
+ var result = (function(){ return _(arguments).compact().length; })(0, 1, false, 2, false, 3);
+ equals(result, 3, 'works on an arguments object');
});
-
+
test("arrays: flatten", function() {
var list = [1, [2], [3, [[[4]]]]];
equals(_.flatten(list).join(', '), '1, 2, 3, 4', 'can flatten nested arrays');
+ var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]);
+ equals(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
});
-
+
test("arrays: without", function() {
var list = [1, 2, 1, 0, 3, 1, 4];
equals(_.without(list, 0, 1).join(', '), '2, 3, 4', 'can remove all instances of an object');
+ var result = (function(){ return _.without(arguments, 0, 1); })(1, 2, 1, 0, 3, 1, 4);
+ equals(result.join(', '), '2, 3, 4', 'works on an arguments object');
});
-
+
test("arrays: uniq", function() {
var list = [1, 2, 1, 3, 1, 4];
equals(_.uniq(list).join(', '), '1, 2, 3, 4', 'can find the unique values of an unsorted array');
-
+
var list = [1, 1, 1, 2, 2, 3];
equals(_.uniq(list, true).join(', '), '1, 2, 3', 'can find the unique values of a sorted array faster');
+
+ var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4);
+ equals(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
});
-
+
test("arrays: intersect", 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(result.join(''), 'moe', 'works an an arguments object');
});
-
+
test('arrays: zip', function() {
var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];
var stooges = _.zip(names, ages, leaders);
equals(String(stooges), 'moe,30,true,larry,40,,curly,50,', 'zipped together arrays of different lengths');
});
-
+
test("arrays: indexOf", function() {
var numbers = [1, 2, 3];
numbers.indexOf = null;
equals(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
+ var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
+ equals(result, 1, 'works on an arguments object');
});
-
+
test("arrays: lastIndexOf", function() {
var numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0];
numbers.lastIndexOf = null;
equals(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function');
equals(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
+ var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0);
+ equals(result, 5, 'works on an arguments object');
});
-
- test("arrays: tail", function() {
- var numbers = [1, 2, 3, 4];
- equals(_.tail(numbers).join(", "), "2, 3, 4");
- });
-
- test("arrays: init", function() {
- var numbers = [1, 2, 3, 4];
- equals(_.init(numbers).join(", "), "1, 2, 3");
- });
-
- test("arrays: reverse", function() {
- var numbers = [1, 2, 4, 6];
- equals(_.reverse(numbers).join(", "), "6, 4, 2, 1");
- });
-
+
});
diff --git a/test/utility.js b/test/utility.js
index 897d0ceec..6fd19af93 100644
--- a/test/utility.js
+++ b/test/utility.js
@@ -31,12 +31,12 @@ $(document).ready(function() {
});
test("utility: functions", function() {
- var expected = ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact",
+ var expected = ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact",
"compose","defer", "delay", "detect", "each", "every", "extend", "filter", "first",
"flatten", "foldl", "foldr", "forEach", "functions", "head", "identity", "include",
- "indexOf", "init", "inject", "intersect", "invoke", "isArray", "isElement", "isEmpty", "isEqual",
+ "indexOf", "inject", "intersect", "invoke", "isArray", "isElement", "isEmpty", "isEqual",
"isFunction", "isNumber", "isString", "isUndefined", "keys", "last", "lastIndexOf", "map", "max",
- "methods", "min", "pluck", "reduce", "reduceRight", "reject", "reverse", "select",
+ "methods", "min", "pluck", "reduce", "reduceRight", "reject", "rest", "select",
"size", "some", "sortBy", "sortedIndex", "tail", "template", "toArray", "uniq",
"uniqueId", "values", "without", "wrap", "zip"];
ok(_(expected).isEqual(_.methods()), 'provides a sorted list of functions');
diff --git a/underscore-min.js b/underscore-min.js
index dbaff85cd..f8466a228 100644
--- a/underscore-min.js
+++ b/underscore-min.js
@@ -1,14 +1,14 @@
-(function(){var j=this,m=j._;function i(a){this._wrapped=a}var l=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;b.VERSION="0.4.4";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(a.length)for(var e=0,f=a.length;e=e.computed&&(e={value:f,computed:g})});
+return e};b.include=function(a,c){if(b.isArray(a))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck=function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});
return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;gf?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e=0;c--)arguments=[a[c].apply(this,arguments)];return arguments[0]}};b.keys=function(a){return b.map(a,function(c,d){return d})};b.values=function(a){return b.map(a,b.identity)};b.extend=function(a,c){for(var d in c)a[d]=
-c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a,e=typeof c;if(d!=e)return false;if(a==c)return true;if(a.isEqual)return a.isEqual(c);if(b.isNumber(a)&&b.isNumber(c)&&isNaN(a)&&isNaN(c))return true;if(d!=="object")return false;d=b.keys(a);e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return(b.isArray(a)?a:b.values(a)).length==
-0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return Object.prototype.toString.call(a)=="[object Array]"};b.isFunction=function(a){return Object.prototype.toString.call(a)=="[object Function]"};b.isString=function(a){return Object.prototype.toString.call(a)=="[object String]"};b.isNumber=function(a){return Object.prototype.toString.call(a)=="[object Number]"};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=m;return this};b.identity=
-function(a){return a};b.breakLoop=function(){throw l;};var n=0;b.uniqueId=function(a){var c=n++;return a?a+c:c};b.functions=function(){var a=[];for(var c in b)Object.prototype.hasOwnProperty.call(b,c)&&a.push(c);return b.without(a,"VERSION","prototype","noConflict").sort()};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,
-"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.methods=b.functions;function k(a,c){return c?b(a).chain():a}b.each(b.functions(),function(a){i.prototype[a]=function(){Array.prototype.unshift.call(arguments,this._wrapped);return k(b[a].apply(b,arguments),this._chain)}});b.each(["pop","push","reverse","shift",
-"sort","splice","unshift"],function(a){i.prototype[a]=function(){Array.prototype[a].apply(this._wrapped,arguments);return k(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){i.prototype[a]=function(){return k(Array.prototype[a].apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
+(e=g+1):(f=g)}return e};b.toArray=function(a){if(!a)return[];if(b.isArray(a))return a;return b.map(a,function(c){return c})};b.size=function(a){return b.toArray(a).length};b.first=function(a,c){return c?Array.prototype.slice.call(a,0,c):a[0]};b.rest=function(a,c){return Array.prototype.slice.call(a,b.isUndefined(c)?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));
+c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c?b.last(d)!=e:!b.include(d,e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e=0;c--)arguments=[a[c].apply(this,arguments)];return arguments[0]}};b.keys=function(a){return b.map(a,function(c,d){return d})};b.values=function(a){return b.map(a,
+b.identity)};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a,e=typeof c;if(d!=e)return false;if(a==c)return true;if(a.isEqual)return a.isEqual(c);if(b.isNumber(a)&&b.isNumber(c)&&isNaN(a)&&isNaN(c))return true;if(d!=="object")return false;d=b.keys(a);e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};
+b.isEmpty=function(a){return(b.isArray(a)?a:b.values(a)).length==0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return Object.prototype.toString.call(a)=="[object Array]"};b.isFunction=function(a){return Object.prototype.toString.call(a)=="[object Function]"};b.isString=function(a){return Object.prototype.toString.call(a)=="[object String]"};b.isNumber=function(a){return Object.prototype.toString.call(a)=="[object Number]"};b.isUndefined=function(a){return typeof a==
+"undefined"};b.noConflict=function(){j._=m;return this};b.identity=function(a){return a};b.breakLoop=function(){throw l;};var n=0;b.uniqueId=function(a){var c=n++;return a?a+c:c};b.functions=function(){var a=[];for(var c in b)Object.prototype.hasOwnProperty.call(b,c)&&a.push(c);return b.without(a,"VERSION","prototype","noConflict").sort()};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,
+"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;function k(a,c){return c?b(a).chain():a}b.each(b.functions(),function(a){i.prototype[a]=function(){Array.prototype.unshift.call(arguments,this._wrapped);return k(b[a].apply(b,arguments),
+this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){i.prototype[a]=function(){Array.prototype[a].apply(this._wrapped,arguments);return k(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){i.prototype[a]=function(){return k(Array.prototype[a].apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
diff --git a/underscore.js b/underscore.js
index ad6dbecac..69851fb02 100644
--- a/underscore.js
+++ b/underscore.js
@@ -31,7 +31,7 @@
if (typeof exports !== 'undefined') exports._ = _;
// Current version.
- _.VERSION = '0.4.4';
+ _.VERSION = '0.4.5';
/*------------------------ Collection Functions: ---------------------------*/
@@ -156,7 +156,7 @@
// Invoke a method with arguments on every item in a collection.
_.invoke = function(obj, method) {
- var args = _.toArray(arguments).slice(2);
+ var args = _.rest(arguments, 2);
return _.map(obj, function(value) {
return (method ? value[method] : value).apply(value, args);
});
@@ -228,9 +228,17 @@
/*-------------------------- Array Functions: ------------------------------*/
- // Get the first element of an array.
- _.first = function(array) {
- return array[0];
+ // Get the first element of an array. Passing "n" will return the first N
+ // values in the array. Aliased as "head".
+ _.first = function(array, n) {
+ return n ? Array.prototype.slice.call(array, 0, n) : array[0];
+ };
+
+ // 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.
+ _.rest = function(array, index) {
+ return Array.prototype.slice.call(array, _.isUndefined(index) ? 1 : index);
};
// Get the last element of an array.
@@ -254,7 +262,7 @@
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
- var values = array.slice.call(arguments, 0);
+ var values = _.rest(arguments);
return _.select(array, function(value){ return !_.include(values, value); });
};
@@ -270,7 +278,7 @@
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersect = function(array) {
- var rest = _.toArray(arguments).slice(1);
+ var rest = _.rest(arguments);
return _.select(_.uniq(array), function(item) {
return _.all(rest, function(other) {
return _.indexOf(other, item) >= 0;
@@ -305,49 +313,23 @@
while (i--) if (array[i] === item) return i;
return -1;
};
-
- // Returns everything but the first entry of the array. Conceptually the
- // same as calling shift(), but doesn't mutate the array passed in.
- _.tail = function(array) {
- var tail = _.clone(array);
- tail.shift();
- return tail;
- };
-
- // Returns everything but the last entry of the array. Conceptually the
- // same as calling pop(), but doesn't mutate the array passed in.
- _.init = function(array) {
- var init = _.clone(array);
- init.pop();
- return init;
- };
-
- // Returns a new array, with the entries or the passed-in array in reverse
- // order.
- _.reverse = function(array) {
- var reverse = _.clone(array);
- return reverse.reverse();
- };
/* ----------------------- Function Functions: -----------------------------*/
// Create a function bound to a given object (assigning 'this', and arguments,
// optionally). Binding with arguments is also known as 'curry'.
_.bind = function(func, context) {
- context = context || root;
- var args = _.toArray(arguments).slice(2);
+ var args = _.rest(arguments, 2);
return function() {
- var a = args.concat(_.toArray(arguments));
- return func.apply(context, a);
+ return func.apply(context || root, args.concat(_.toArray(arguments)));
};
};
// Bind all of an object's methods to that object. Useful for ensuring that
// all callbacks defined on an object belong to it.
_.bindAll = function() {
- var args = _.toArray(arguments);
- var context = args.pop();
- _.each(args, function(methodName) {
+ var context = Array.prototype.pop.call(arguments);
+ _.each(arguments, function(methodName) {
context[methodName] = _.bind(context[methodName], context);
});
};
@@ -355,14 +337,14 @@
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
- var args = _.toArray(arguments).slice(2);
+ var args = _.rest(arguments, 2);
return setTimeout(function(){ return func.apply(func, args); }, wait);
};
// Defers a function, scheduling it to run after the current call stack has
// cleared.
_.defer = function(func) {
- return _.delay.apply(_, [func, 1].concat(_.toArray(arguments).slice(1)));
+ return _.delay.apply(_, [func, 1].concat(_.rest(arguments)));
};
// Returns the first function passed as an argument to the second,
@@ -524,13 +506,14 @@
/*------------------------------- Aliases ----------------------------------*/
- _.head = _.first;
_.forEach = _.each;
_.foldl = _.inject = _.reduce;
_.foldr = _.reduceRight;
_.filter = _.select;
_.every = _.all;
_.some = _.any;
+ _.head = _.first;
+ _.tail = _.rest;
_.methods = _.functions;
/*------------------------ Setup the OOP Wrapper: --------------------------*/