make the new faster isEmpty a little safer too

This commit is contained in:
Jeremy Ashkenas
2010-02-24 12:43:57 -05:00
parent 2c8fbe7875
commit 7824d63ce8
3 changed files with 90 additions and 90 deletions

View File

@@ -4,7 +4,6 @@
<meta http-equiv="content-type" content="text/html;charset=UTF-8" /> <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="chrome=1"> <meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Underscore.js</title> <title>Underscore.js</title>
<script src="underscore.js"></script>
<style> <style>
body { body {
font-size: 16px; font-size: 16px;
@@ -89,7 +88,7 @@
as well as more specialized helpers: function binding, javascript as well as more specialized helpers: function binding, javascript
templating, deep equality testing, and so on. It delegates to built-in templating, deep equality testing, and so on. It delegates to built-in
functions, if present, so modern browsers will use the functions, if present, so modern browsers will use the
native implementations of <b>forEach</b>, <b>map</b>, <b>reduce</b>, native implementations of <b>forEach</b>, <b>map</b>, <b>reduce</b>,
<b>filter</b>, <b>every</b>, <b>some</b> and <b>indexOf</b>. <b>filter</b>, <b>every</b>, <b>some</b> and <b>indexOf</b>.
</p> </p>
@@ -102,7 +101,7 @@
The unabridged source code is The unabridged source code is
<a href="http://github.com/documentcloud/underscore/">available on GitHub</a>. <a href="http://github.com/documentcloud/underscore/">available on GitHub</a>.
</p> </p>
<p> <p>
<i>Underscore is an open-source component of <a href="http://documentcloud.org/">DocumentCloud</a>.</i> <i>Underscore is an open-source component of <a href="http://documentcloud.org/">DocumentCloud</a>.</i>
</p> </p>
@@ -162,10 +161,10 @@ _(lyrics).chain()
=&gt; {lumberjack : 2, all : 4, night : 2 ... }</pre> =&gt; {lumberjack : 2, all : 4, night : 2 ... }</pre>
<p> <p>
In addition, the In addition, the
<a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array">Array prototype's methods</a> <a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array">Array prototype's methods</a>
are proxied through the chained Underscore object, so you can slip a are proxied through the chained Underscore object, so you can slip a
<tt>reverse</tt> or a <tt>push</tt> into your chain, and continue to <tt>reverse</tt> or a <tt>push</tt> into your chain, and continue to
modify the array. modify the array.
</p> </p>
@@ -209,7 +208,7 @@ _(lyrics).chain()
<a href="#isEqual">isEqual</a>, <a href="#isEmpty">isEmpty</a>, <a href="#isElement">isElement</a>, <a href="#isEqual">isEqual</a>, <a href="#isEmpty">isEmpty</a>, <a href="#isElement">isElement</a>,
<a href="#isArray">isArray</a>, <a href="#isArguments">isArguments</a>, <a href="#isFunction">isFunction</a>, <a href="#isString">isString</a>, <a href="#isArray">isArray</a>, <a href="#isArguments">isArguments</a>, <a href="#isFunction">isFunction</a>, <a href="#isString">isString</a>,
<a href="#isNumber">isNumber</a>, <a href="#isDate">isDate</a>, <a href="#isRegExp">isRegExp</a> <a href="#isNumber">isNumber</a>, <a href="#isDate">isDate</a>, <a href="#isRegExp">isRegExp</a>
<a href="#isNaN">isNaN</a>, <a href="#isNull">isNull</a>, <a href="#isNaN">isNaN</a>, <a href="#isNull">isNull</a>,
<a href="#isUndefined">isUndefined</a> <a href="#isUndefined">isUndefined</a>
</span> </span>
</p> </p>
@@ -240,7 +239,7 @@ _(lyrics).chain()
function. The <b>iterator</b> is bound to the <b>context</b> object, if one is function. The <b>iterator</b> is bound to the <b>context</b> object, if one is
passed. Each invocation of <b>iterator</b> is called with three arguments: passed. Each invocation of <b>iterator</b> is called with three arguments:
<tt>(element, index, list)</tt>. If <b>list</b> is a JavaScript object, <b>iterator</b>'s <tt>(element, index, list)</tt>. If <b>list</b> is a JavaScript object, <b>iterator</b>'s
arguments will be <tt>(value, key, list)</tt>. Use <a href="#breakLoop"><tt>breakLoop</tt></a> arguments will be <tt>(value, key, list)</tt>. Use <a href="#breakLoop"><tt>breakLoop</tt></a>
to break out of the iteration. Delegates to the native to break out of the iteration. Delegates to the native
<b>forEach</b> function if it exists. <b>forEach</b> function if it exists.
</p> </p>
@@ -461,7 +460,7 @@ _.size({one : 1, two : 2, three : 3});
</pre> </pre>
<h2>Array Functions</h2> <h2>Array Functions</h2>
<p> <p>
<i>Note: All array functions will also work on the <b>arguments</b> object.</i> <i>Note: All array functions will also work on the <b>arguments</b> object.</i>
</p> </p>
@@ -470,7 +469,7 @@ _.size({one : 1, two : 2, three : 3});
<b class="header">first</b><code>_.first(array, [n])</code> <b class="header">first</b><code>_.first(array, [n])</code>
<span class="alias">Alias: <b>head</b></span> <span class="alias">Alias: <b>head</b></span>
<br /> <br />
Returns the first element of an <b>array</b>. Passing <b>n</b> will Returns the first element of an <b>array</b>. Passing <b>n</b> will
return the first <b>n</b> elements of the array. return the first <b>n</b> elements of the array.
</p> </p>
<pre> <pre>
@@ -738,7 +737,7 @@ _.values({one : 1, two : 2, three : 3});
<span class="alias">Alias: <b>methods</b></span> <span class="alias">Alias: <b>methods</b></span>
<br /> <br />
Returns a sorted list of the names of every method in an object &mdash; Returns a sorted list of the names of every method in an object &mdash;
that is to say, the name of every function property of the object. that is to say, the name of every function property of the object.
</p> </p>
<pre> <pre>
_.functions(_); _.functions(_);
@@ -770,7 +769,7 @@ _.clone({name : 'moe'});
<p id="tap"> <p id="tap">
<b class="header">tap</b><code>_.tap(object, interceptor)</code> <b class="header">tap</b><code>_.tap(object, interceptor)</code>
<br /> <br />
Invokes <b>interceptor</b> with the <b>object</b>, and then returns <b>object</b>. Invokes <b>interceptor</b> with the <b>object</b>, and then returns <b>object</b>.
The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.
</p> </p>
<pre> <pre>
@@ -960,14 +959,14 @@ moe === _.identity(moe);
<b class="header">breakLoop</b><code>_.breakLoop()</code> <b class="header">breakLoop</b><code>_.breakLoop()</code>
<br /> <br />
Breaks out of the current loop iteration. Similar to the <tt>break</tt> Breaks out of the current loop iteration. Similar to the <tt>break</tt>
keyword in regular "for" loop, but works within an iterator function. keyword in regular "for" loop, but works within an iterator function.
Uses the native <tt>StopIteration</tt> object in JavaScript 1.7 compliant Uses the native <tt>StopIteration</tt> object in JavaScript 1.7 compliant
browsers. browsers.
</p> </p>
<pre> <pre>
var result = null; var result = null;
_.each([1, 2, 3], function(num) { _.each([1, 2, 3], function(num) {
if ((result = num) == 2) _.breakLoop(); if ((result = num) == 2) _.breakLoop();
}); });
result; result;
=&gt; 2</pre> =&gt; 2</pre>
@@ -1009,18 +1008,18 @@ _.template(list, {people : ['moe', 'curly', 'larry']});
template settings to use different symbols to set off interpolated code. template settings to use different symbols to set off interpolated code.
Define <b>start</b> and <b>end</b> tokens, and an <b>interpolate</b> regex Define <b>start</b> and <b>end</b> tokens, and an <b>interpolate</b> regex
to match expressions that should be evaluated and inserted. For example, to match expressions that should be evaluated and inserted. For example,
to perform to perform
<a href="http://github.com/janl/mustache.js#readme">Mustache.js</a> <a href="http://github.com/janl/mustache.js#readme">Mustache.js</a>
style templating: style templating:
</p> </p>
<pre> <pre>
_.templateSettings = { _.templateSettings = {
start : '{{', start : '{{',
end : '}}', end : '}}',
interpolate : /\{\{(.+?)\}\}/g interpolate : /\{\{(.+?)\}\}/g
}; };
var template = _.template("Hello {{ name }}!"); var template = _.template("Hello {{ name }}!");
template({name : "Mustache"}); template({name : "Mustache"});
=&gt; "Hello Mustache!"</pre> =&gt; "Hello Mustache!"</pre>
@@ -1055,119 +1054,119 @@ _([1, 2, 3]).value();
</pre> </pre>
<h2 id="duck_typing">Duck Typing</h2> <h2 id="duck_typing">Duck Typing</h2>
<p> <p>
The <b>isType</b> (<tt>isArray</tt>, <tt>isFunction</tt>, <tt>isString</tt> ...) family of type-checking The <b>isType</b> (<tt>isArray</tt>, <tt>isFunction</tt>, <tt>isString</tt> ...) family of type-checking
functions use property detection to do their work, which, although functions use property detection to do their work, which, although
orders of magnitude faster than the alternative, isn't entirely safe when dealing orders of magnitude faster than the alternative, isn't entirely safe when dealing
with objects that are used as hashes, where arbitrary strings are being with objects that are used as hashes, where arbitrary strings are being
set for the keys. It's entirely possible for an object to masquerade as set for the keys. It's entirely possible for an object to masquerade as
another type, if you're setting properties with names like "concat" and another type, if you're setting properties with names like "concat" and
"charCodeAt". So be aware. "charCodeAt". So be aware.
</p> </p>
<h2>Links &amp; Suggested Reading</h2> <h2>Links &amp; Suggested Reading</h2>
<p> <p>
<a href="http://mirven.github.com/underscore.lua/">Underscore.lua</a>, <a href="http://mirven.github.com/underscore.lua/">Underscore.lua</a>,
a Lua port of the functions that are applicable in both languages. a Lua port of the functions that are applicable in both languages.
Includes OOP-wrapping and chaining. Includes OOP-wrapping and chaining.
The <a href="http://github.com/mirven/underscore.lua">source</a> is The <a href="http://github.com/mirven/underscore.lua">source</a> is
available on GitHub. available on GitHub.
</p> </p>
<p> <p>
Ruby's <a href="http://ruby-doc.org/core/classes/Enumerable.html">Enumerable</a> module. Ruby's <a href="http://ruby-doc.org/core/classes/Enumerable.html">Enumerable</a> module.
</p> </p>
<p> <p>
<a href="http://www.prototypejs.org/">Prototype.js</a>, which provides <a href="http://www.prototypejs.org/">Prototype.js</a>, which provides
JavaScript with collection functions in the manner closest to Ruby's Enumerable. JavaScript with collection functions in the manner closest to Ruby's Enumerable.
</p> </p>
<p> <p>
Oliver Steele's Oliver Steele's
<a href="http://osteele.com/sources/javascript/functional/">Functional JavaScript</a>, <a href="http://osteele.com/sources/javascript/functional/">Functional JavaScript</a>,
which includes comprehensive higher-order function support as well as string lambdas. which includes comprehensive higher-order function support as well as string lambdas.
</p> </p>
<p> <p>
Python's <a href="http://docs.python.org/library/itertools.html">itertools</a>. Python's <a href="http://docs.python.org/library/itertools.html">itertools</a>.
</p> </p>
<h2>Change Log</h2> <h2>Change Log</h2>
<p> <p>
<b class="header">0.5.8</b><br /> <b class="header">0.5.8</b><br />
Fixed Underscore's collection functions to work on Fixed Underscore's collection functions to work on
<a href="https://developer.mozilla.org/En/DOM/NodeList">NodeLists</a> and <a href="https://developer.mozilla.org/En/DOM/NodeList">NodeLists</a> and
<a href="https://developer.mozilla.org/En/DOM/HTMLCollection">HTMLCollections</a> <a href="https://developer.mozilla.org/En/DOM/HTMLCollection">HTMLCollections</a>
once more, thanks to once more, thanks to
<a href="http://github.com/jmtulloss">Justin Tulloss</a>. <a href="http://github.com/jmtulloss">Justin Tulloss</a>.
</p> </p>
<p> <p>
<b class="header">0.5.7</b><br /> <b class="header">0.5.7</b><br />
A safer implementation of <tt>_.isArguments</tt>, and a A safer implementation of <tt>_.isArguments</tt>, and a
faster <tt>_.isNumber</tt>,<br />thanks to faster <tt>_.isNumber</tt>,<br />thanks to
<a href="http://jedschmidt.com/">Jed Schmidt</a>. <a href="http://jedschmidt.com/">Jed Schmidt</a>.
</p> </p>
<p> <p>
<b class="header">0.5.6</b><br /> <b class="header">0.5.6</b><br />
Customizable delimiters for <tt>_.template</tt>, contributed by Customizable delimiters for <tt>_.template</tt>, contributed by
<a href="http://github.com/iamnoah">Noah Sloan</a>. <a href="http://github.com/iamnoah">Noah Sloan</a>.
</p> </p>
<p> <p>
<b class="header">0.5.5</b><br /> <b class="header">0.5.5</b><br />
Fix for a bug in MobileSafari's OOP-wrapper, with the arguments object. Fix for a bug in MobileSafari's OOP-wrapper, with the arguments object.
</p> </p>
<p> <p>
<b class="header">0.5.4</b><br /> <b class="header">0.5.4</b><br />
Fix for multiple single quotes within a template string for Fix for multiple single quotes within a template string for
<tt>_.template</tt>. See: <tt>_.template</tt>. See:
<a href="http://www.west-wind.com/Weblog/posts/509108.aspx">Rick Strahl's blog post</a>. <a href="http://www.west-wind.com/Weblog/posts/509108.aspx">Rick Strahl's blog post</a>.
</p> </p>
<p> <p>
<b class="header">0.5.2</b><br /> <b class="header">0.5.2</b><br />
New implementations of <tt>isArray</tt>, <tt>isDate</tt>, <tt>isFunction</tt>, New implementations of <tt>isArray</tt>, <tt>isDate</tt>, <tt>isFunction</tt>,
<tt>isNumber</tt>, <tt>isRegExp</tt>, and <tt>isString</tt>, thanks to <tt>isNumber</tt>, <tt>isRegExp</tt>, and <tt>isString</tt>, thanks to
a suggestion from a suggestion from
<a href="http://www.broofa.com/">Robert Kieffer</a>. <a href="http://www.broofa.com/">Robert Kieffer</a>.
Instead of doing <tt>Object#toString</tt> Instead of doing <tt>Object#toString</tt>
comparisons, they now check for expected properties, which is less safe, comparisons, they now check for expected properties, which is less safe,
but more than an order of magnitude faster. Most other Underscore but more than an order of magnitude faster. Most other Underscore
functions saw minor speed improvements as a result. functions saw minor speed improvements as a result.
<a href="http://dolzhenko.org/">Evgeniy Dolzhenko</a> <a href="http://dolzhenko.org/">Evgeniy Dolzhenko</a>
contributed <tt>_.tap</tt>, contributed <tt>_.tap</tt>,
<a href="http://ruby-doc.org/core-1.9/classes/Object.html#M000191">similar to Ruby 1.9's</a>, <a href="http://ruby-doc.org/core-1.9/classes/Object.html#M000191">similar to Ruby 1.9's</a>,
which is handy for injecting side effects (like logging) into chained calls. which is handy for injecting side effects (like logging) into chained calls.
</p> </p>
<p> <p>
<b class="header">0.5.1</b><br /> <b class="header">0.5.1</b><br />
Added an <tt>_.isArguments</tt> function. Lots of little safety checks Added an <tt>_.isArguments</tt> function. Lots of little safety checks
and optimizations contributed by and optimizations contributed by
<a href="http://github.com/iamnoah/">Noah Sloan</a> and Andri Möll. <a href="http://github.com/iamnoah/">Noah Sloan</a> and Andri Möll.
</p> </p>
<p> <p>
<b class="header">0.5.0</b><br /> <b class="header">0.5.0</b><br />
<b>[API Changes]</b> <tt>_.bindAll</tt> now takes the context object as <b>[API Changes]</b> <tt>_.bindAll</tt> now takes the context object as
its first parameter. If no method names are passed, all of the context its first parameter. If no method names are passed, all of the context
object's methods are bound to it, enabling chaining and easier binding. object's methods are bound to it, enabling chaining and easier binding.
<tt>_.functions</tt> now takes a single argument and returns the names <tt>_.functions</tt> now takes a single argument and returns the names
of its Function properties. Calling <tt>_.functions(_)</tt> will get you of its Function properties. Calling <tt>_.functions(_)</tt> will get you
the previous behavior. the previous behavior.
Added <tt>_.isRegExp</tt> so that <tt>isEqual</tt> can now test for RegExp equality. Added <tt>_.isRegExp</tt> so that <tt>isEqual</tt> can now test for RegExp equality.
All of the "is" functions have been shrunk down into a single definition. All of the "is" functions have been shrunk down into a single definition.
<a href="http://github.com/grayrest/">Karl Guertin</a> contributed patches. <a href="http://github.com/grayrest/">Karl Guertin</a> contributed patches.
</p> </p>
<p> <p>
<b class="header">0.4.7</b><br /> <b class="header">0.4.7</b><br />
Added <tt>isDate</tt>, <tt>isNaN</tt>, and <tt>isNull</tt>, for completeness. Added <tt>isDate</tt>, <tt>isNaN</tt>, and <tt>isNull</tt>, for completeness.
@@ -1175,48 +1174,48 @@ _([1, 2, 3]).value();
or Dates. <tt>_.keys</tt> is now <small><i><b>25%&ndash;2X</b></i></small> faster (depending on your or Dates. <tt>_.keys</tt> is now <small><i><b>25%&ndash;2X</b></i></small> faster (depending on your
browser) which speeds up the functions that rely on it, such as <tt>_.each</tt>. browser) which speeds up the functions that rely on it, such as <tt>_.each</tt>.
</p> </p>
<p> <p>
<b class="header">0.4.6</b><br /> <b class="header">0.4.6</b><br />
Added the <tt>range</tt> function, a port of the Added the <tt>range</tt> function, a port of the
<a href="http://docs.python.org/library/functions.html#range">Python <a href="http://docs.python.org/library/functions.html#range">Python
function of the same name</a>, for generating flexibly-numbered lists function of the same name</a>, for generating flexibly-numbered lists
of integers. Original patch contributed by of integers. Original patch contributed by
<a href="http://github.com/kylichuku">Kirill Ishanov</a>. <a href="http://github.com/kylichuku">Kirill Ishanov</a>.
</p> </p>
<p> <p>
<b class="header">0.4.5</b><br /> <b class="header">0.4.5</b><br />
Added <tt>rest</tt> for Arrays and arguments objects, and aliased Added <tt>rest</tt> for Arrays and arguments objects, and aliased
<tt>first</tt> as <tt>head</tt>, and <tt>rest</tt> as <tt>tail</tt>, <tt>first</tt> as <tt>head</tt>, and <tt>rest</tt> as <tt>tail</tt>,
thanks to <a href="http://github.com/lukesutton/">Luke Sutton</a>'s patches. thanks to <a href="http://github.com/lukesutton/">Luke Sutton</a>'s patches.
Added tests ensuring that all Underscore Array functions also work on Added tests ensuring that all Underscore Array functions also work on
<i>arguments</i> objects. <i>arguments</i> objects.
</p> </p>
<p> <p>
<b class="header">0.4.4</b><br /> <b class="header">0.4.4</b><br />
Added <tt>isString</tt>, and <tt>isNumber</tt>, for consistency. Fixed Added <tt>isString</tt>, and <tt>isNumber</tt>, for consistency. Fixed
<tt>_.isEqual(NaN, NaN)</tt> to return <i>true</i> (which is debatable). <tt>_.isEqual(NaN, NaN)</tt> to return <i>true</i> (which is debatable).
</p> </p>
<p> <p>
<b class="header">0.4.3</b><br /> <b class="header">0.4.3</b><br />
Started using the native <tt>StopIteration</tt> object in browsers that support it. Started using the native <tt>StopIteration</tt> object in browsers that support it.
Fixed Underscore setup for CommonJS environments. Fixed Underscore setup for CommonJS environments.
</p> </p>
<p> <p>
<b class="header">0.4.2</b><br /> <b class="header">0.4.2</b><br />
Renamed the unwrapping function to <tt>value</tt>, for clarity. Renamed the unwrapping function to <tt>value</tt>, for clarity.
</p> </p>
<p> <p>
<b class="header">0.4.1</b><br /> <b class="header">0.4.1</b><br />
Chained Underscore objects now support the Array prototype methods, so Chained Underscore objects now support the Array prototype methods, so
that you can perform the full range of operations on a wrapped array that you can perform the full range of operations on a wrapped array
without having to break your chain. Added a <tt>breakLoop</tt> method without having to break your chain. Added a <tt>breakLoop</tt> method
to <b>break</b> in the middle of any Underscore iteration. Added an to <b>break</b> in the middle of any Underscore iteration. Added an
<tt>isEmpty</tt> function that works on arrays and objects. <tt>isEmpty</tt> function that works on arrays and objects.
</p> </p>
@@ -1288,5 +1287,8 @@ _([1, 2, 3]).value();
</div> </div>
<!-- Include Underscore, so you can play with it in the console. -->
<script type="text/javascript" src="underscore.js"></script>
</body> </body>
</html> </html>

View File

@@ -60,6 +60,7 @@ $(document).ready(function() {
ok(_.isEmpty([]), '[] is empty'); ok(_.isEmpty([]), '[] is empty');
ok(!_.isEmpty({one : 1}), '{one : 1} is not empty'); ok(!_.isEmpty({one : 1}), '{one : 1} is not empty');
ok(_.isEmpty({}), '{} is empty'); ok(_.isEmpty({}), '{} is empty');
ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty');
ok(_.isEmpty(null), 'null is empty'); ok(_.isEmpty(null), 'null is empty');
ok(_.isEmpty(), 'undefined is empty'); ok(_.isEmpty(), 'undefined is empty');
@@ -102,7 +103,7 @@ $(document).ready(function() {
ok(_.isArguments(args), 'but the arguments object is an arguments object'); ok(_.isArguments(args), 'but the arguments object is an arguments object');
ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array'); ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array');
ok(!_.isArguments([1,2,3]), 'and not vanilla arrays.'); ok(!_.isArguments([1,2,3]), 'and not vanilla arrays.');
ok(_.isArguments(iArguments), 'event from another frame'); ok(_.isArguments(iArguments), 'even from another frame');
}); });
test("objects: isArray", function() { test("objects: isArray", function() {

View File

@@ -67,18 +67,17 @@
// The cornerstone, an each implementation. // The cornerstone, an each implementation.
// Handles objects implementing forEach, arrays, and raw objects. // Handles objects implementing forEach, arrays, and raw objects.
// Delegates to JavaScript 1.6's native forEach if available. // Delegates to JavaScript 1.6's native forEach if available.
var each = var each = _.forEach = function(obj, iterator, context) {
_.forEach = function(obj, iterator, context) {
var index = 0; var index = 0;
try { try {
if (obj.forEach === nativeForEach) { if (obj.forEach === nativeForEach) {
obj.forEach(iterator, context); obj.forEach(iterator, context);
} else if (_.isNumber(obj.length)) { } else if (_.isNumber(obj.length)) {
for (var i=0, l=obj.length; i<l; i++) iterator.call(context, obj[i], i, obj); for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj);
} else { } else {
for (var key in obj) for (var key in obj) {
if (hasOwnProperty.call(obj, key)) if (hasOwnProperty.call(obj, key)) iterator.call(context, obj[key], key, obj);
iterator.call(context, obj[key], key, obj); }
} }
} catch(e) { } catch(e) {
if (e != breaker) throw e; if (e != breaker) throw e;
@@ -339,7 +338,7 @@
var args = _.toArray(arguments); var args = _.toArray(arguments);
var length = _.max(_.pluck(args, 'length')); var length = _.max(_.pluck(args, 'length'));
var results = new Array(length); var results = new Array(length);
for (var i=0; i<length; i++) results[i] = _.pluck(args, String(i)); for (var i = 0; i < length; i++) results[i] = _.pluck(args, String(i));
return results; return results;
}; };
@@ -349,7 +348,7 @@
// Delegates to JavaScript 1.8's native indexOf if available. // Delegates to JavaScript 1.8's native indexOf if available.
_.indexOf = function(array, item) { _.indexOf = function(array, item) {
if (array.indexOf === nativeIndexOf) return array.indexOf(item); if (array.indexOf === nativeIndexOf) return array.indexOf(item);
for (var i=0, l=array.length; i<l; i++) if (array[i] === item) return i; for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
return -1; return -1;
}; };
@@ -513,7 +512,7 @@
// Is a given array or object empty? // Is a given array or object empty?
_.isEmpty = function(obj) { _.isEmpty = function(obj) {
if (_.isArray(obj)) return obj.length === 0; if (_.isArray(obj)) return obj.length === 0;
for (var k in obj) return false; for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
return true; return true;
}; };
@@ -588,11 +587,9 @@
return value; return value;
}; };
// run a function n times. // Run a function n times.
// looks good in wrapper form: _.times = function (n, iterator, context) {
// _(3).times(alert) for (var i = 0; i < n; i++) iterator.call(context, i);
_.times = function (n, fn, context) {
for (var i = 0; i < n; i++) fn.call(context, i);
}; };
// Break out of the middle of an iteration. // Break out of the middle of an iteration.