From 978255b7780952f7603d24f78485b1d90a6e2dfa Mon Sep 17 00:00:00 2001 From: Peter Jihoon Kim Date: Fri, 13 Jan 2012 20:09:50 +0800 Subject: [PATCH 1/8] added "collect" alias for "map" --- test/collections.js | 3 +++ underscore.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/collections.js b/test/collections.js index 46bcdf2af..cff9763ce 100644 --- a/test/collections.js +++ b/test/collections.js @@ -35,6 +35,9 @@ $(document).ready(function() { var doubled = _.map([1, 2, 3], function(num){ return num * 2; }); equals(doubled.join(', '), '2, 4, 6', 'doubled numbers'); + doubled = _.collect([1, 2, 3], function(num){ return num * 2; }); + equals(doubled.join(', '), '2, 4, 6', 'aliased as "collect"'); + var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3}); equals(tripled.join(', '), '3, 6, 9', 'tripled numbers with context'); diff --git a/underscore.js b/underscore.js index 096a4800d..9c8bcc2b0 100644 --- a/underscore.js +++ b/underscore.js @@ -89,7 +89,7 @@ // Return the results of applying the iterator to each element. // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = function(obj, iterator, context) { + _.map = _.collect = function(obj, iterator, context) { var results = []; if (obj == null) return results; if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); From 3898597b12fc80a70e5585d5a99c66ce8b52b6d8 Mon Sep 17 00:00:00 2001 From: Arlo Breault Date: Wed, 18 Jan 2012 20:34:54 -0800 Subject: [PATCH 2/8] has --- underscore.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/underscore.js b/underscore.js index 9c8bcc2b0..b6671d50b 100644 --- a/underscore.js +++ b/underscore.js @@ -26,8 +26,7 @@ // Create quick reference variables for speed access to core prototypes. var slice = ArrayProto.slice, unshift = ArrayProto.unshift, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; + toString = ObjProto.toString; // All **ECMAScript 5** native function implementations that we hope to use // are declared here. @@ -80,7 +79,7 @@ } } else { for (var key in obj) { - if (hasOwnProperty.call(obj, key)) { + if (_.has(obj, key)) { if (iterator.call(context, obj[key], key, obj) === breaker) return; } } @@ -506,7 +505,7 @@ hasher || (hasher = _.identity); return function() { var key = hasher.apply(this, arguments); - return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); }; }; @@ -612,7 +611,7 @@ _.keys = nativeKeys || function(obj) { if (obj !== Object(obj)) throw new TypeError('Invalid object'); var keys = []; - for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key; + for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; return keys; }; @@ -733,17 +732,17 @@ if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; // Deep compare objects. for (var key in a) { - if (hasOwnProperty.call(a, key)) { + if (_.has(a, key)) { // Count the expected number of properties. size++; // Deep compare each member. - if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break; + if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break; } } // Ensure that both objects contain the same number of properties. if (result) { for (key in b) { - if (hasOwnProperty.call(b, key) && !(size--)) break; + if (_.has(b, key) && !(size--)) break; } result = !size; } @@ -762,7 +761,7 @@ // An "empty" object has no enumerable own-properties. _.isEmpty = function(obj) { if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; - for (var key in obj) if (hasOwnProperty.call(obj, key)) return false; + for (var key in obj) if (_.has(obj, key)) return false; return true; }; @@ -788,7 +787,7 @@ }; if (!_.isArguments(arguments)) { _.isArguments = function(obj) { - return !!(obj && hasOwnProperty.call(obj, 'callee')); + return !!(obj && _.has(obj, 'callee')); }; } @@ -838,6 +837,11 @@ return obj === void 0; }; + // Has own property? + _.has = function(obj, key) { + return ObjProto.hasOwnProperty.call(obj, key); + }; + // Utility Functions // ----------------- From 99c17c4a0daa23371a1fd69ad6519da5b77b8c4b Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 23 Jan 2012 15:48:35 -0500 Subject: [PATCH 3/8] reverting an old change -- _.extend should absolutely copy undefined values. --- test/objects.js | 2 +- underscore.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/objects.js b/test/objects.js index 6d432033a..0105d608a 100644 --- a/test/objects.js +++ b/test/objects.js @@ -38,7 +38,7 @@ $(document).ready(function() { result = _.extend({x:'x'}, {a:'a', x:2}, {a:'b'}); ok(_.isEqual(result, {x:2, a:'b'}), 'extending from multiple source objects last property trumps'); result = _.extend({}, {a: void 0, b: null}); - equals(_.keys(result).join(''), 'b', 'extend does not copy undefined values'); + equals(_.keys(result).join(''), 'ab', 'extend does not copy undefined values'); }); test("objects: defaults", function() { diff --git a/underscore.js b/underscore.js index 096a4800d..bf42fe006 100644 --- a/underscore.js +++ b/underscore.js @@ -635,7 +635,7 @@ _.extend = function(obj) { each(slice.call(arguments, 1), function(source) { for (var prop in source) { - if (source[prop] !== void 0) obj[prop] = source[prop]; + obj[prop] = source[prop]; } }); return obj; From 5ed8b6e6ce0d0d724ce3fc8fd5a516fd1e535970 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 23 Jan 2012 16:05:56 -0500 Subject: [PATCH 4/8] using a cached reference to hasOwnProperty (again) --- underscore.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/underscore.js b/underscore.js index b787a6648..debc3481d 100644 --- a/underscore.js +++ b/underscore.js @@ -26,7 +26,8 @@ // Create quick reference variables for speed access to core prototypes. var slice = ArrayProto.slice, unshift = ArrayProto.unshift, - toString = ObjProto.toString; + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; // All **ECMAScript 5** native function implementations that we hope to use // are declared here. @@ -839,7 +840,7 @@ // Has own property? _.has = function(obj, key) { - return ObjProto.hasOwnProperty.call(obj, key); + return hasOwnProperty.call(obj, key); }; // Utility Functions From d959c019f8a8dcfb7ed68a4fd6dfc43bda516931 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 23 Jan 2012 16:10:49 -0500 Subject: [PATCH 5/8] clarify that sortBy is ascending. --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index afef3e5ac..3c0ce397f 100644 --- a/index.html +++ b/index.html @@ -521,8 +521,8 @@ _.min(numbers);

sortBy_.sortBy(list, iterator, [context])
- Returns a sorted copy of list, ranked by the results of running - each value through iterator. + Returns a sorted copy of list, ranked in ascending order by the + results of running each value through iterator.

 _.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });

From a8c956fe6ae16a22d11a48cd77a956c2ad7125d6 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas 
Date: Mon, 23 Jan 2012 17:03:19 -0500
Subject: [PATCH 6/8] Fixes #436 -- document the second argument to _.flatten

---
 index.html | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/index.html b/index.html
index 3c0ce397f..69a6e13be 100644
--- a/index.html
+++ b/index.html
@@ -656,13 +656,17 @@ _.compact([0, 1, false, 2, '', 3]);
 

- flatten_.flatten(array) + flatten_.flatten(array, [shallow])
- Flattens a nested array (the nesting can be to any depth). + Flattens a nested array (the nesting can be to any depth). If you + pass shallow, the array will only be flattened a single level.

-_.flatten([1, [2], [3, [[[4]]]]]);
+_.flatten([1, [2], [3, [[4]]]]);
 => [1, 2, 3, 4];
+
+_.flatten([1, [2], [3, [[4]]]], true);
+=> [1, 2, 3, [[4]]];
 

From cdf43ea742271d9f612e639d76e5ed86ebb7c3fa Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 23 Jan 2012 17:33:48 -0500 Subject: [PATCH 7/8] Fixes #429 -- don't escape slash escapes in the body of interpolations... --- test/utility.js | 5 ++++- underscore.js | 14 +++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/test/utility.js b/test/utility.js index 30ba3a940..7bc5cb44b 100644 --- a/test/utility.js +++ b/test/utility.js @@ -57,6 +57,9 @@ $(document).ready(function() { var backslashTemplate = _.template("<%= thing %> is \\ridanculous"); equals(backslashTemplate({thing: 'This'}), "This is \\ridanculous"); + var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>'); + equals(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.'); + var fancyTemplate = _.template("

    <% \ for (key in people) { \ %>
  • <%= people[key] %>
  • <% } %>
"); @@ -65,7 +68,7 @@ $(document).ready(function() { var escapedCharsInJavascriptTemplate = _.template("
    <% _.each(numbers.split('\\n'), function(item) { %>
  • <%= item %>
  • <% }) %>
"); result = escapedCharsInJavascriptTemplate({numbers: "one\ntwo\nthree\nfour"}); - equals(result, "
  • one
  • two
  • three
  • four
", 'Can use escaped characters (e.g. \\n) in Javascript') + equals(result, "
  • one
  • two
  • three
  • four
", 'Can use escaped characters (e.g. \\n) in Javascript'); var namespaceCollisionTemplate = _.template("<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %>
\">
<% }); %>"); result = namespaceCollisionTemplate({ diff --git a/underscore.js b/underscore.js index debc3481d..6687ded01 100644 --- a/underscore.js +++ b/underscore.js @@ -897,6 +897,12 @@ // guaranteed not to match. var noMatch = /.^/; + // Within an interpolation, evaluation, or escaping, remove HTML escaping + // that had been previously added. + var unescape = function(code) { + return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'"); + }; + // JavaScript micro-templating, similar to John Resig's implementation. // Underscore templating handles arbitrary delimiters, preserves whitespace, // and correctly escapes quotes within interpolated code. @@ -907,15 +913,13 @@ str.replace(/\\/g, '\\\\') .replace(/'/g, "\\'") .replace(c.escape || noMatch, function(match, code) { - return "',_.escape(" + code.replace(/\\'/g, "'") + "),'"; + return "',_.escape(" + unescape(code) + "),'"; }) .replace(c.interpolate || noMatch, function(match, code) { - return "'," + code.replace(/\\'/g, "'") + ",'"; + return "'," + unescape(code) + ",'"; }) .replace(c.evaluate || noMatch, function(match, code) { - return "');" + code.replace(/\\'/g, "'") - .replace(/[\r\n\t]/g, ' ') - .replace(/\\\\/g, '\\') + ";__p.push('"; + return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('"; }) .replace(/\r/g, '\\r') .replace(/\n/g, '\\n') From eeea70c457db3aebaef5b9251661f779844758fe Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 23 Jan 2012 17:56:29 -0500 Subject: [PATCH 8/8] Underscore 1.3.1 --- docs/underscore.html | 69 +++++++++++++++++++++++--------------------- index.html | 40 +++++++++++++++++++++++-- package.json | 3 +- underscore-min.js | 50 ++++++++++++++++---------------- underscore.js | 4 +-- 5 files changed, 101 insertions(+), 65 deletions(-) diff --git a/docs/underscore.html b/docs/underscore.html index c92a32016..0c2bd9652 100644 --- a/docs/underscore.html +++ b/docs/underscore.html @@ -1,4 +1,4 @@ - underscore.js

underscore.js

Underscore.js 1.3.0
+      underscore.js           
hasher||(hasher=_.identity);returnfunction(){varkey=hasher.apply(this,arguments); - returnhasOwnProperty.call(memo,key)?memo[key]:(memo[key]=func.apply(this,arguments)); + return_.has(memo,key)?memo[key]:(memo[key]=func.apply(this,arguments));};}; Delegates to ECMAScript 5's native Object.keys

str.replace(/\\/g,'\\\\').replace(/'/g,"\\'").replace(c.escape||noMatch,function(match,code){ - return"',_.escape("+code.replace(/\\'/g,"'")+"),'"; + return"',_.escape("+unescape(code)+"),'";}).replace(c.interpolate||noMatch,function(match,code){ - return"',"+code.replace(/\\'/g,"'")+",'"; + return"',"+unescape(code)+",'";}).replace(c.evaluate||noMatch,function(match,code){ - return"');"+code.replace(/\\'/g,"'") - .replace(/[\r\n\t]/g,' ') - .replace(/\\\\/g,'\\')+";__p.push('"; + return"');"+unescape(code).replace(/[\r\n\t]/g,' ')+";__p.push('";}).replace(/\r/g,'\\r').replace(/\n/g,'\\n') @@ -590,19 +593,19 @@ and correctly escapes quotes within interpolated code.

returnfunction(data){returnfunc.call(this,data,_);}; - };if((name=='shift'||name=='splice')&&length===0)deletewrapped[0];returnresult(wrapped,this._chain);}; - });

underscore.js

Underscore.js 1.3.1
 (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
 Underscore is freely distributable under the MIT license.
 Portions of Underscore are inspired or borrowed from Prototype,
@@ -31,7 +31,7 @@ for Closure Compiler "advanced" mode.

exports._ = _; } else { root['_'] = _; - }

Current version.

  _.VERSION = '1.3.0';

Collection Functions

The cornerstone, an each implementation, aka forEach. + }

Current version.

  _.VERSION = '1.3.1';

Collection Functions

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.

  var each = _.each = _.forEach = function(obj, iterator, context) {
     if (obj == null) return;
@@ -43,13 +43,13 @@ Delegates to ECMAScript 5's native forEach if avai
       }
     } else {
       for (var key in obj) {
-        if (hasOwnProperty.call(obj, key)) {
+        if (_.has(obj, key)) {
           if (iterator.call(context, obj[key], key, obj) === breaker) return;
         }
       }
     }
   };

Return the results of applying the iterator to each element. -Delegates to ECMAScript 5's native map if available.

  _.map = function(obj, iterator, context) {
+Delegates to ECMAScript 5's native map if available.

  _.map = _.collect = function(obj, iterator, context) {
     var results = [];
     if (obj == null) return results;
     if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
@@ -349,7 +349,7 @@ all callbacks defined on an object belong to it.

Delays a function for the given number of milliseconds, and then calls it with the arguments supplied.

  _.delay = function(func, wait) {
@@ -425,7 +425,7 @@ consuming the return value of the function that follows.

  _.keys = nativeKeys || function(obj) {
     if (obj !== Object(obj)) throw new TypeError('Invalid object');
     var keys = [];
-    for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
+    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
     return keys;
   };

Retrieve the values of an object's properties.

  _.values = function(obj) {
     return _.map(obj, _.identity);
@@ -439,7 +439,7 @@ Aliased as methods

};

Extend a given object with all the properties in passed-in object(s).

  _.extend = function(obj) {
     each(slice.call(arguments, 1), function(source) {
       for (var prop in source) {
-        if (source[prop] !== void 0) obj[prop] = source[prop];
+        obj[prop] = source[prop];
       }
     });
     return obj;
@@ -487,11 +487,11 @@ unique nested structures.

} } } else {

Objects with different constructors are not equivalent.

      if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;

Deep compare objects.

      for (var key in a) {
-        if (hasOwnProperty.call(a, key)) {

Count the expected number of properties.

          size++;

Deep compare each member.

          if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break;
+        if (_.has(a, key)) {

Count the expected number of properties.

          size++;

Deep compare each member.

          if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;
         }
       }

Ensure that both objects contain the same number of properties.

      if (result) {
         for (key in b) {
-          if (hasOwnProperty.call(b, key) && !(size--)) break;
+          if (_.has(b, key) && !(size--)) break;
         }
         result = !size;
       }
@@ -502,7 +502,7 @@ unique nested structures.

};

Is a given array, string, or object empty? An "empty" object has no enumerable own-properties.

  _.isEmpty = function(obj) {
     if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
-    for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
+    for (var key in obj) if (_.has(obj, key)) return false;
     return true;
   };

Is a given value a DOM element?

  _.isElement = function(obj) {
     return !!(obj && obj.nodeType == 1);
@@ -516,7 +516,7 @@ Delegates to ECMA5's native Array.isArray

}; if (!_.isArguments(arguments)) { _.isArguments = function(obj) { - return !!(obj && hasOwnProperty.call(obj, 'callee')); + return !!(obj && _.has(obj, 'callee')); }; }

Is a given value a function?

  _.isFunction = function(obj) {
     return toString.call(obj) == '[object Function]';
@@ -535,34 +535,39 @@ Delegates to ECMA5's native Array.isArray

return obj === null; };

Is a given variable undefined?

  _.isUndefined = function(obj) {
     return obj === void 0;
-  };

Utility Functions

Run Underscore.js in noConflict mode, returning the _ variable to its + };

Has own property?

  _.has = function(obj, key) {
+    return hasOwnProperty.call(obj, key);
+  };

Utility Functions

Run Underscore.js in noConflict mode, returning the _ variable to its previous owner. Returns a reference to the Underscore object.

  _.noConflict = function() {
     root._ = previousUnderscore;
     return this;
-  };

Keep the identity function around for default iterators.

  _.identity = function(value) {
+  };

Keep the identity function around for default iterators.

  _.identity = function(value) {
     return value;
-  };

Run a function n times.

  _.times = function (n, iterator, context) {
+  };

Run a function n times.

  _.times = function (n, iterator, context) {
     for (var i = 0; i < n; i++) iterator.call(context, i);
-  };

Escape a string for HTML interpolation.

  _.escape = function(string) {
+  };

Escape a string for HTML interpolation.

  _.escape = function(string) {
     return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
-  };

Add your own custom functions to the Underscore object, ensuring that + };

Add your own custom functions to the Underscore object, ensuring that they're correctly added to the OOP wrapper as well.

  _.mixin = function(obj) {
     each(_.functions(obj), function(name){
       addToWrapper(name, _[name] = obj[name]);
     });
-  };

Generate a unique integer id (unique within the entire client session). + };

Generate a unique integer id (unique within the entire client session). Useful for temporary DOM ids.

  var idCounter = 0;
   _.uniqueId = function(prefix) {
     var id = idCounter++;
     return prefix ? prefix + id : id;
-  };

By default, Underscore uses ERB-style template delimiters, change the + };

By default, Underscore uses ERB-style template delimiters, change the following template settings to use alternative delimiters.

  _.templateSettings = {
     evaluate    : /<%([\s\S]+?)%>/g,
     interpolate : /<%=([\s\S]+?)%>/g,
     escape      : /<%-([\s\S]+?)%>/g
-  };

When customizing templateSettings, if you don't want to define an + };

When customizing templateSettings, if you don't want to define an interpolation, evaluation or escaping regex, we need one that is -guaranteed not to match.

  var noMatch = /.^/;

JavaScript micro-templating, similar to John Resig's implementation. +guaranteed not to match.

  var noMatch = /.^/;

Within an interpolation, evaluation, or escaping, remove HTML escaping +that had been previously added.

  var unescape = function(code) {
+    return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'");
+  };

JavaScript micro-templating, similar to John Resig's implementation. Underscore templating handles arbitrary delimiters, preserves whitespace, and correctly escapes quotes within interpolated code.

  _.template = function(str, data) {
     var c  = _.templateSettings;
@@ -571,15 +576,13 @@ and correctly escapes quotes within interpolated code.

Add a "chain" function, which will delegate to the wrapper.

  _.chain = function(obj) {
+  };

Add a "chain" function, which will delegate to the wrapper.

  _.chain = function(obj) {
     return _(obj).chain();
-  };

The OOP Wrapper

If Underscore is called as a function, it returns a wrapped object that + };

The OOP Wrapper

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.

  var wrapper = function(obj) { this._wrapped = obj; };

Expose wrapper.prototype as _.prototype

  _.prototype = wrapper.prototype;

Helper function to continue chaining intermediate results.

  var result = function(obj, chain) {
+underscore functions. Wrapped objects may be chained.

  var wrapper = function(obj) { this._wrapped = obj; };

Expose wrapper.prototype as _.prototype

  _.prototype = wrapper.prototype;

Helper function to continue chaining intermediate results.

  var result = function(obj, chain) {
     return chain ? _(obj).chain() : obj;
-  };

A method to easily add functions to the OOP wrapper.

  var addToWrapper = function(name, func) {
+  };

A method to easily add functions to the OOP wrapper.

  var addToWrapper = function(name, func) {
     wrapper.prototype[name] = function() {
       var args = slice.call(arguments);
       unshift.call(args, this._wrapped);
       return result(func.apply(_, args), this._chain);
     };
-  };

Add all of the Underscore functions to the wrapper object.

  _.mixin(_);

Add all mutator Array functions to the wrapper.

  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+  };

Add all of the Underscore functions to the wrapper object.

  _.mixin(_);

Add all mutator Array functions to the wrapper.

  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
     var method = ArrayProto[name];
     wrapper.prototype[name] = function() {
       var wrapped = this._wrapped;
@@ -611,15 +614,15 @@ underscore functions. Wrapped objects may be chained.

Add all accessor Array functions to the wrapper.

  each(['concat', 'join', 'slice'], function(name) {
+  });

Add all accessor Array functions to the wrapper.

  each(['concat', 'join', 'slice'], function(name) {
     var method = ArrayProto[name];
     wrapper.prototype[name] = function() {
       return result(method.apply(this._wrapped, arguments), this._chain);
     };
-  });

Start chaining a wrapped Underscore object.

  wrapper.prototype.chain = function() {
+  });

Start chaining a wrapped Underscore object.

  wrapper.prototype.chain = function() {
     this._chain = true;
     return this;
-  };

Extracts the result from a wrapped and chained object.

  wrapper.prototype.value = function() {
+  };

Extracts the result from a wrapped and chained object.

  wrapper.prototype.value = function() {
     return this._wrapped;
   };
 
diff --git a/index.html b/index.html
index 69a6e13be..52c967122 100644
--- a/index.html
+++ b/index.html
@@ -134,7 +134,7 @@
   
+ +

+ has_.has(object, key) +
+ Does the object contain the given key? Identical to + object.hasOwnProperty(key), but uses a safe reference to the + hasOwnProperty function, in case it's been + overridden accidentally. +

+
+_.has({a: 1, b: 2, c: 3}, "b");
+=> true
 

@@ -1469,6 +1484,25 @@ _([1, 2, 3]).value();

Change Log

+

+ 1.3.1Jan. 23, 2012
+

    +
  • + Added an _.has function, as a safer way to use hasOwnProperty. +
  • +
  • + Added _.collect as an alias for _.map. Smalltalkers, rejoice. +
  • +
  • + Reverted an old change so that _.extend will correctly copy + over keys with undefined values again. +
  • +
  • + Bugfix to stop escaping slashes within interpolations in _.template. +
  • +
+

+

1.3.0Jan. 11, 2012

    diff --git a/package.json b/package.json index 0749177b4..4a2e3ca72 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,7 @@ "homepage" : "http://documentcloud.github.com/underscore/", "keywords" : ["util", "functional", "server", "client", "browser"], "author" : "Jeremy Ashkenas ", - "contributors" : [], "repository" : {"type": "git", "url": "git://github.com/documentcloud/underscore.git"}, "main" : "underscore.js", - "version" : "1.3.0" + "version" : "1.3.1" } diff --git a/underscore-min.js b/underscore-min.js index fe1ffd20a..5b55f32be 100644 --- a/underscore-min.js +++ b/underscore-min.js @@ -1,31 +1,31 @@ -// Underscore.js 1.3.0 +// Underscore.js 1.3.1 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. // Underscore is freely distributable under the MIT license. // Portions of Underscore are inspired or borrowed from Prototype, // Oliver Steele's Functional, and John Resig's Micro-Templating. // For all details and documentation: // http://documentcloud.github.com/underscore -(function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== -c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c, -h)&&!f--)break;g=!f}}d.pop();return g}var s=this,G=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,H=k.unshift,l=p.toString,m=p.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,q=k.indexOf,D=k.lastIndexOf,p=Array.isArray,I=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else s._=b;b.VERSION="1.3.0";var j=b.each= -b.forEach=function(a,c,b){if(a!=null)if(w&&a.forEach===w)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a==null&&(a= -[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a, -c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b, -a,g,h)))return o});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return q&&a.indexOf===q?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=function(a, -c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d= -b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<= -0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=I||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments,1), -function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)}; -b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"}; -b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),function(c){J(c,b[c]= -a[c])})};var K=0;b.uniqueId=function(a){var b=K++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var u=/.^/;b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||u,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate||u,function(a,b){return"',"+b.replace(/\\'/g, -"'")+",'"}).replace(d.evaluate||u,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ").replace(/\\\\/g,"\\")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var v=function(a,c){return c?b(a).chain():a},J=function(a,c){n.prototype[a]=function(){var a= -i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain= -true;return this};n.prototype.value=function(){return this._wrapped}}).call(this); +(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c, +h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each= +b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a== +null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect= +function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e= +e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck= +function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a, +c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}}; +b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)}; +b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"}; +b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a), +function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+ +u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]= +function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain= +true;return this};m.prototype.value=function(){return this._wrapped}}).call(this); diff --git a/underscore.js b/underscore.js index 6687ded01..208d4cd89 100644 --- a/underscore.js +++ b/underscore.js @@ -1,4 +1,4 @@ -// Underscore.js 1.3.0 +// Underscore.js 1.3.1 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. // Underscore is freely distributable under the MIT license. // Portions of Underscore are inspired or borrowed from Prototype, @@ -62,7 +62,7 @@ } // Current version. - _.VERSION = '1.3.0'; + _.VERSION = '1.3.1'; // Collection Functions // --------------------