From 5eec4e5d22dae5518b585f36e867112aac0606df Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sun, 8 Nov 2009 12:07:10 -0500 Subject: [PATCH] adding breakLoop --- index.html | 240 +++++++++++++++++++++++++----------------------- test/utility.js | 11 ++- underscore.js | 13 ++- 3 files changed, 146 insertions(+), 118 deletions(-) diff --git a/index.html b/index.html index 22f09bc5e..06de0f1b9 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ - Underscore.js + Underscore.js - +
- +

Underscore.js

- +

- Underscore is a + Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support that you would expect in - Prototype.js - (or Ruby), - but without extending any of the built-in JavaScript objects. It's the + Prototype.js + (or Ruby), + but without extending any of the built-in JavaScript objects. It's the tie to go along with jQuery's tux.

- +

- Underscore provides 45-odd functions that support both the usual - functional suspects: map, select, invoke — - as well as more specialized helpers: function binding, javascript - templating, deep equality testing, and so on. It delegates to built-in - functions, if present, so - JavaScript 1.6 - compliant browsers will use the - native implementations of forEach, map, filter, + Underscore provides 45-odd functions that support both the usual + functional suspects: map, select, invoke — + as well as more specialized helpers: function binding, javascript + templating, deep equality testing, and so on. It delegates to built-in + functions, if present, so + JavaScript 1.6 + compliant browsers will use the + native implementations of forEach, map, filter, every, some and indexOf.

- +

Underscore includes a complete Test & Benchmark Suite for your perusal.

- +

- The unabridged source code is + The unabridged source code is available on GitHub.

- +

Downloads (Right-click, and use "Save As")

- +

@@ -116,28 +116,28 @@

- +

Object-Oriented and Functional Styles

- +

- You can use Underscore in either an object-oriented or a functional style, - depending on your preference. The following two lines of code are + You can use Underscore in either an object-oriented or a functional style, + depending on your preference. The following two lines of code are identical ways to double a list of numbers.

- +
 _.map([1, 2, 3], function(n){ return n * 2; });
 _([1, 2, 3]).map(function(n){ return n * 2; });

Using the object-oriented style allows you to chain together methods. Calling - chain on a wrapped object will cause all future method calls to - return wrapped objects as well. When you've finished the computation, + chain on a wrapped object will cause all future method calls to + return wrapped objects as well. When you've finished the computation, use get to retrieve the final value. Here's an example of chaining - together a map/flatten/reduce, in order to get the word count of + together a map/flatten/reduce, in order to get the word count of every word in a song.

- +
 var lyrics = [
   {line : 1, words : "I'm a lumberjack and I'm okay"},
@@ -149,73 +149,73 @@ var lyrics = [
 _(lyrics).chain()
   .map(function(line) { return line.words.split(' '); })
   .flatten()
-  .reduce({}, function(counts, word) { 
+  .reduce({}, function(counts, word) {
     counts[word] = (counts[word] || 0) + 1;
     return counts;
 }).get();
 
 => {lumberjack : 2, all : 4, night : 2 ... }
- +

Table of Contents

- +

Collections -
- each, map, - reduce, reduceRight, - detect, select, - reject, all, - any, include, - invoke, pluck, - max, min, - sortBy, sortedIndex, +
+ each, map, + reduce, reduceRight, + detect, select, + reject, all, + any, include, + invoke, pluck, + max, min, + sortBy, sortedIndex, toArray, size

- +

Arrays
- first, last, - compact, flatten, without, uniq, + first, last, + compact, flatten, without, uniq, intersect, zip, indexOf, lastIndexOf

- +

Functions
- bind, bindAll, delay, + bind, bindAll, delay, defer, wrap, compose

- +

Objects
- keys, values, - extend, clone, - isEqual, isEmpty, isElement, + keys, values, + extend, clone, + isEqual, isEmpty, isElement, isArray, isFunction, isUndefined

- +

Utility
noConflict, - identity, uniqueId, - template + identity, breakLoop, + uniqueId, template

- +

Chaining
chain, get

- +
- +

Collection Functions (Arrays or Objects)

- +

each_.each(list, iterator, [context]) Alias: forEach @@ -224,19 +224,19 @@ _(lyrics).chain() function. The iterator is bound to the context object, if one is passed. Each invocation of iterator is called with three arguments: (element, index, list). If list is a JavaScript object, iterator's - arguments will be (value, key, list). If the list has an each - method of its own, it will be used instead. Delegates to the native + arguments will be (value, key, list). If the list has an each + method of its own, it will be used instead. Delegates to the native forEach function if it exists.

 _.each([1, 2, 3], function(num){ alert(num); });
 => alerts each number in turn...
- +

map_.map(list, iterator, [context])
- Produces a new array of values by mapping each value in list - through a transformation function (iterator). If the native + Produces a new array of values by mapping each value in list + through a transformation function (iterator). If the native map method exists, it will be used instead.

@@ -247,7 +247,7 @@ _.map([1, 2, 3], function(num){ return num * 3 });
         reduce_.reduce(list, memo, iterator, [context])
         Aliases: inject, foldl
         
- Also known as inject and foldl, reduce boils down a + Also known as inject and foldl, reduce boils down a list of values into a single value. Memo is the initial state of the reduction, and each successive step of it should be returned by iterator. @@ -261,7 +261,7 @@ var sum = _.reduce([1, 2, 3], 0, function(memo, num){ return memo + num }); reduceRight_.reduceRight(list, memo, iterator, [context]) Alias: foldr
- The right-associative version of reduce. Delegates to the + The right-associative version of reduce. Delegates to the JavaScript 1.8 version of reduceRight, if it exists. Foldr is not as useful in JavaScript as it would be in a language with lazy evaluation. @@ -275,8 +275,8 @@ var flat = _.reduceRight(list, [], function(a, b) { return a.concat(b); });

detect_.detect(list, iterator, [context])
- Looks through each value in the list, returning the first one that - passes a truth test (iterator). The function returns as + Looks through each value in the list, returning the first one that + passes a truth test (iterator). The function returns as soon as it finds an acceptable element, and doesn't traverse the entire list.

@@ -314,7 +314,7 @@ var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); 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 + 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.

@@ -364,7 +364,7 @@ _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');

pluck_.pluck(list, propertyName)
- An convenient version of what is perhaps the most common use-case for + An convenient version of what is perhaps the most common use-case for map: extracting a list of property values.

@@ -443,9 +443,9 @@ _.sortedIndex([10, 20, 30, 40, 50], 35);
 _.size({one : 1, two : 2, three : 3});
 => 3
 
- +

Array Functions

- +

first_.first(array)
@@ -469,8 +469,8 @@ _.last([3, 2, 1]);

compact_.compact(array)
- Returns a copy of the array with all falsy values removed. - In JavaScript, false, null, 0, "", + Returns a copy of the array with all falsy values removed. + In JavaScript, false, null, 0, "", undefined and NaN are all falsy.

@@ -537,7 +537,7 @@ _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
       

indexOf_.indexOf(array, value)
- Returns the index at which value can be found in the array, + Returns the index at which value can be found in the array, or -1 if value is not present in the array. Uses the native indexOf function unless it's missing.

@@ -549,8 +549,8 @@ _.indexOf([1, 2, 3], 2);

lastIndexOf_.lastIndexOf(array, value)
- Returns the index of the last occurrence of value in the array, - or -1 if value is not present. Uses the native lastIndexOf + Returns the index of the last occurrence of value in the array, + or -1 if value is not present. Uses the native lastIndexOf function if possible.

@@ -566,7 +566,7 @@ _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
         Bind a function to a context object, meaning that whenever
         the function is called, the value of this will be the context.
         Optionally, bind arguments to the function to pre-fill them,
-        also known as currying. 
+        also known as currying.
       

 var func = function(greeting){ return greeting + ': ' + this.name };
@@ -578,15 +578,15 @@ func();
       

bindAll_.bindAll(*methodNames, context)
- Binds a number of methods on the context object, specified by + Binds a number of methods on the context object, specified by methodNames, to be run in the context of that object whenever they are invoked. Very handy for binding functions that are going to be used - as event handlers, which would otherwise be invoked with a fairly useless + as event handlers, which would otherwise be invoked with a fairly useless this.

 var buttonView = {
-  label   : 'underscore', 
+  label   : 'underscore',
   onClick : function(){ alert('clicked: ' + this.label); },
   onHover : function(){ console.log('hovering: ' + this.label); }
 };
@@ -624,8 +624,8 @@ _.defer(function(){ alert('deferred'); });
       

wrap_.wrap(function, wrapper)
- Wraps the first function inside of the wrapper function, - passing it as the first argument. This allows the wrapper to + Wraps the first function inside of the wrapper function, + passing it as the first argument. This allows the wrapper to execute code before and after the function runs, adjust the arguments, and execute it conditionally.

@@ -641,7 +641,7 @@ hello();

compose_.compose(*functions)
- Returns the composition of a list of functions, where each function + Returns the composition of a list of functions, where each function consumes the return value of the function that follows. In math terms, composing the functions f(), g(), and h() produces f(g(h())). @@ -679,7 +679,7 @@ _.values({one : 1, two : 2, three : 3});

extend_.extend(destination, source)
- Copy all of the properties in the source object over to the + Copy all of the properties in the source object over to the destination object.

@@ -768,7 +768,7 @@ _.isUndefined(window.missingVariable);
 

Utility Functions

- +

noConflict_.noConflict()
@@ -781,20 +781,34 @@ var underscore = _.noConflict();

identity_.identity(value)
- Returns the same value that is used as the argument. In math: + Returns the same value that is used as the argument. In math: f(x) = x
- This function looks useless, but is used throughout Underscore as + This function looks useless, but is used throughout Underscore as a default iterator.

 var moe = {name : 'moe'};
 moe === _.identity(moe);
-=> true
+=> true
+ +

+ breakLoop_.breakLoop() +
+ Breaks out of the current loop iteration. Similar to the break + keyword in regular "for" loop, but works within an iterator function. +

+
+var result = null;
+_.each([1, 2, 3], function(num) { 
+  if ((result = num) == 2) _.breakLoop(); 
+});
+result;
+=> 2

uniqueId_.uniqueId([prefix])
- Generate a globally-unique id for client-side models or DOM elements + Generate a globally-unique id for client-side models or DOM elements that need one. If prefix is passed, the id will be appended to it.

@@ -819,7 +833,7 @@ _.functions();
         Compiles JavaScript templates into functions that can be evaluated
         for rendering. Useful for rendering complicated bits of HTML from JSON
         data sources. Template functions can both interpolate variables, using
- <%= … %>, as well as execute arbitrary JavaScript code, with + <%= … %>, as well as execute arbitrary JavaScript code, with <% … %>. When you evaluate a template function, pass in a context object that has properties corresponding to the template's free variables. If you're writing a one-off, you can pass the context @@ -834,10 +848,10 @@ compiled({name : 'moe'}); var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>"; _.template(list, {people : ['moe', 'curly', 'larry']}); => "<li>moe</li><li>curly</li><li>larry</li>" -
+

Chaining

- +

chain_(obj).chain()
@@ -861,30 +875,30 @@ _([1, 2, 3]).get();

Change Log

- +

0.4.0
- All Underscore functions can now be called in an object-oriented style, + All Underscore functions can now be called in an object-oriented style, like so: _([1, 2, 3]).map(...);. Original patch provided by - Marc-André Cournoyer. + Marc-André Cournoyer. Wrapped objects can be chained through multiple - method invocations. A functions method + method invocations. A functions method was added, providing a sorted list of all the functions in Underscore.

- +

0.3.3
Added the JavaScript 1.8 function reduceRight. Aliased it as foldr, and aliased reduce as foldl.

- +

0.3.2
- Now runs on stock Rhino + Now runs on stock Rhino interpreters with: load("underscore.js"). Added identity as a utility function.

- +

0.3.1
All iterators are now passed in the original collection as their third @@ -892,29 +906,29 @@ _([1, 2, 3]).get(); objects is now called with (value, key, collection), for details see _.each.

- +

0.3.0
- Added Dmitry Baranovskiy's - comprehensive optimizations, merged in - Kris Kowal's patches to make Underscore - CommonJS and + Added Dmitry Baranovskiy's + comprehensive optimizations, merged in + Kris Kowal's patches to make Underscore + CommonJS and Narwhal compliant.

- +

0.2.0
Added compose and lastIndexOf, renamed inject to - reduce, added aliases for inject, filter, + reduce, added aliases for inject, filter, every, some, and forEach.

- +

0.1.1
- Added noConflict, so that the "Underscore" object can be assigned to + Added noConflict, so that the "Underscore" object can be assigned to other variables.

- +

0.1.0
Initial release of Underscore.js. @@ -925,9 +939,9 @@ _([1, 2, 3]).get(); A DocumentCloud Project

- +
- +
diff --git a/test/utility.js b/test/utility.js index 171340830..4515ba4c4 100644 --- a/test/utility.js +++ b/test/utility.js @@ -14,6 +14,15 @@ $(document).ready(function() { var moe = {name : 'moe'}; equals(_.identity(moe), moe, 'moe is the same as his identity'); }); + + test('utility: breakLoop', function() { + var result = null; + _([1,2,3,4,5,6]).each(function(num) { + result = num; + if (num == 3) _.breakLoop(); + }); + equals(result, 3, 'broke out of a loop'); + }); test("utility: uniqueId", function() { var ids = [], i = 0; @@ -22,7 +31,7 @@ $(document).ready(function() { }); test("utility: functions", function() { - var expected = ["all", "any", "bind", "bindAll", "clone", "compact", "compose", + 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", diff --git a/underscore.js b/underscore.js index b4db3a9c9..748c6e247 100644 --- a/underscore.js +++ b/underscore.js @@ -90,7 +90,7 @@ _.each(obj, function(value, index, list) { if (iterator.call(context, value, index, list)) { result = value; - throw '__break__'; + _.breakLoop(); } }); return result; @@ -123,7 +123,7 @@ if (obj.every) return obj.every(iterator, context); var result = true; _.each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) throw '__break__'; + if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop(); }); return result; }; @@ -135,7 +135,7 @@ if (obj.some) return obj.some(iterator, context); var result = false; _.each(obj, function(value, index, list) { - if (result = iterator.call(context, value, index, list)) throw '__break__'; + if (result = iterator.call(context, value, index, list)) _.breakLoop(); }); return result; }; @@ -146,7 +146,7 @@ if (_.isArray(obj)) return _.indexOf(obj, target) != -1; var found = false; _.each(obj, function(value) { - if (found = value === target) throw '__break__'; + if (found = value === target) _.breakLoop(); }); return found; }; @@ -446,6 +446,11 @@ return value; }; + // Break out of the middle of an iteration. + _.breakLoop = function() { + throw "__break__"; + }; + // Generate a unique integer id (unique within the entire client session). // Useful for temporary DOM ids. var idCounter = 0;