diff --git a/underscore.js b/underscore.js index 87455c6d4..ffacf6b30 100644 --- a/underscore.js +++ b/underscore.js @@ -65,7 +65,7 @@ var each = _.forEach = function(obj, iterator, context) { var index = 0; try { - if (obj.forEach === nativeForEach) { + if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (_.isNumber(obj.length)) { for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj); @@ -83,7 +83,7 @@ // Return the results of applying the iterator to each element. // Delegates to JavaScript 1.6's native map if available. _.map = function(obj, iterator, context) { - if (obj.map === nativeMap) return obj.map(iterator, context); + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); var results = []; each(obj, function(value, index, list) { results.push(iterator.call(context, value, index, list)); @@ -94,7 +94,7 @@ // Reduce builds up a single result from a list of values, aka inject, or foldl. // Delegates to JavaScript 1.8's native reduce if available. _.reduce = function(obj, memo, iterator, context) { - if (obj.reduce === nativeReduce) return obj.reduce(_.bind(iterator, context), memo); + if (nativeReduce && obj.reduce === nativeReduce) return obj.reduce(_.bind(iterator, context), memo); each(obj, function(value, index, list) { memo = iterator.call(context, memo, value, index, list); }); @@ -104,9 +104,9 @@ // The right-associative version of reduce, also known as foldr. Uses // Delegates to JavaScript 1.8's native reduceRight if available. _.reduceRight = function(obj, memo, iterator, context) { - if (obj.reduceRight === nativeReduceRight) return obj.reduceRight(_.bind(iterator, context), memo); + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) return obj.reduceRight(_.bind(iterator, context), memo); var reversed = _.clone(_.toArray(obj)).reverse(); - return reduce(reversed, memo, iterator, context); + return _.reduce(reversed, memo, iterator, context); }; // Return the first value which passes a truth test. @@ -124,7 +124,7 @@ // Return all the elements that pass a truth test. // Delegates to JavaScript 1.6's native filter if available. _.filter = function(obj, iterator, context) { - if (obj.filter === nativeFilter) return obj.filter(iterator, context); + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); var results = []; each(obj, function(value, index, list) { iterator.call(context, value, index, list) && results.push(value); @@ -145,7 +145,7 @@ // Delegates to JavaScript 1.6's native every if available. _.every = function(obj, iterator, context) { iterator = iterator || _.identity; - if (obj.every === nativeEvery) return obj.every(iterator, context); + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); var result = true; each(obj, function(value, index, list) { if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop(); @@ -157,7 +157,7 @@ // Delegates to JavaScript 1.6's native some if available. _.some = function(obj, iterator, context) { iterator = iterator || _.identity; - if (obj.some === nativeSome) return obj.some(iterator, context); + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); var result = false; each(obj, function(value, index, list) { if (result = iterator.call(context, value, index, list)) _.breakLoop(); @@ -167,10 +167,12 @@ // Determine if a given value is included in the array or object using '==='. _.include = function(obj, target) { - if (obj && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - return !! _.detect(obj, function(value) { - return value === target; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + var found = false; + each(obj, function(value) { + if (found = value === target) _.breakLoop(); }); + return found; }; // Invoke a method with arguments on every item in a collection. @@ -271,7 +273,7 @@ // Trim out all falsy values from an array. _.compact = function(array) { - return _.select(array, function(value){ return !!value; }); + return _.filter(array, function(value){ return !!value; }); }; // Return a completely flattened version of an array. @@ -286,7 +288,7 @@ // Return a version of the array that does not contain the specified value(s). _.without = function(array) { var values = _.rest(arguments); - return _.select(array, function(value){ return !_.include(values, value); }); + return _.filter(array, function(value){ return !_.include(values, value); }); }; // Produce a duplicate-free version of the array. If the array has already @@ -302,8 +304,8 @@ // passed-in arrays. _.intersect = function(array) { var rest = _.rest(arguments); - return _.select(_.uniq(array), function(item) { - return _.all(rest, function(other) { + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { return _.indexOf(other, item) >= 0; }); }); @@ -324,7 +326,7 @@ // item in an array, or -1 if the item is not included in the array. // Delegates to JavaScript 1.8's native indexOf if available. _.indexOf = function(array, item) { - if (array.indexOf === nativeIndexOf) return array.indexOf(item); + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; return -1; }; @@ -332,7 +334,7 @@ // Delegates to JavaScript 1.6's native lastIndexOf if available. _.lastIndexOf = function(array, item) { - if (array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); var i = array.length; while (i--) if (array[i] === item) return i; return -1; @@ -428,7 +430,7 @@ // Return a sorted list of the function names available on the object. _.functions = function(obj) { - return _.select(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort(); + return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort(); }; // Extend a given object with all of the properties in a source object. @@ -577,7 +579,7 @@ // 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){ + each(_.functions(obj), function(name){ addToWrapper(name, _[name] = obj[name]); }); }; @@ -601,13 +603,15 @@ // JavaScript templating a-la ERB, pilfered from John Resig's // "Secrets of the JavaScript Ninja", page 83. // Single-quote fix from Rick Strahl's version. + // With alterations for arbitrary delimiters. _.template = function(str, data) { var c = _.templateSettings; + var endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g"); var fn = new Function('obj', 'var p=[],print=function(){p.push.apply(p,arguments);};' + 'with(obj){p.push(\'' + str.replace(/[\r\t\n]/g, " ") - .replace(new RegExp("'(?=[^"+c.end[0]+"]*"+escapeRegExp(c.end)+")","g"),"\t") + .replace(endMatch,"\t") .split("'").join("\\'") .split("\t").join("'") .replace(c.interpolate, "',$1,'")