Underscore.js 1.1.6
(c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
Underscore is freely distributable under the MIT license.
Portions of Underscore are inspired or borrowed from Prototype,
@@ -28,7 +28,7 @@ global object.
|
_._ = _;
} else {
root._ = _;
- } |
| Current version. | |
Collection Functions | |
| The cornerstone, an each implementation, aka forEach.
+ } |
| Current version. | |
Collection Functions | |
| The cornerstone, an each implementation, aka forEach.
Handles objects implementing 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;
@@ -110,7 +110,6 @@ Aliased as select. | }; |
| Determine whether all of the elements match a truth test.
Delegates to ECMAScript 5's native every if available.
Aliased as all. | _.every = _.all = function(obj, iterator, context) {
- iterator = iterator || _.identity;
var result = true;
if (obj == null) return result;
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
@@ -121,7 +120,7 @@ Aliased as all. |
}; |
| Determine if at least one element in the object matches a truth test.
Delegates to ECMAScript 5's native some if available.
Aliased as any. | var any = _.some = _.any = function(obj, iterator, context) {
- iterator = iterator || _.identity;
+ iterator || (iterator = _.identity);
var result = false;
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
@@ -141,7 +140,7 @@ Aliased as contains. | }; |
| Invoke a method (with arguments) on every item in a collection. | _.invoke = function(obj, method) {
var args = slice.call(arguments, 2);
return _.map(obj, function(value) {
- return (method ? value[method] : value).apply(value, args);
+ return (method.call ? method || value : value[method]).apply(value, args);
});
}; |
| Convenience version of a common use case of map: fetching a property. | _.pluck = function(obj, key) {
return _.map(obj, function(value){ return value[key]; });
@@ -173,7 +172,7 @@ Aliased as contains. | }), 'value');
}; |
| Use a comparator function to figure out at what index an object should
be inserted so as to maintain order. Uses binary search. | _.sortedIndex = function(array, obj, iterator) {
- iterator = iterator || _.identity;
+ iterator || (iterator = _.identity);
var low = 0, high = array.length;
while (low < high) {
var mid = (low + high) >> 1;
@@ -274,8 +273,9 @@ the native Python range() function. See
return range;
}; |
Function (ahem) Functions | |
| Create a function bound to a given object (assigning this, and arguments,
optionally). Binding with arguments is also known as curry.
-Delegates to ECMAScript 5's native Function.bind if available. | _.bind = function(func, obj) {
- if (nativeBind && func.bind === nativeBind) return func.bind.apply(func, slice.call(arguments, 1));
+Delegates to ECMAScript 5's native Function.bind if available.
+We check for func.bind first, to fail fast when func is undefined. | _.bind = function(func, obj) {
+ if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
@@ -288,7 +288,7 @@ all callbacks defined on an object belong to it. |
return obj;
};
| Memoize an expensive function by storing its results. | _.memoize = function(func, hasher) {
var memo = {};
- hasher = hasher || _.identity;
+ hasher || (hasher = _.identity);
return function() {
var key = hasher.apply(this, arguments);
return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
@@ -343,95 +343,103 @@ consuming the return value of the function that follows. |
}
return args[0];
};
- };
Object Functions | |
| Retrieve the names of an object's properties.
+ }; |
| Returns a function that will only be executed after being called N times. | _.after = function(times, func) {
+ return function() {
+ if (--times < 1) { return func.apply(this, arguments); }
+ };
+ }; |
Object Functions | |
| Retrieve the names of an object's properties.
Delegates to ECMAScript 5's native Object.keys | _.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;
return keys;
- }; |
| Retrieve the values of an object's properties. | _.values = function(obj) {
+ }; |
| Retrieve the values of an object's properties. | _.values = function(obj) {
return _.map(obj, _.identity);
- }; |
| Return a sorted list of the function names available on the object.
+ }; |
| Return a sorted list of the function names available on the object.
Aliased as methods | _.functions = _.methods = function(obj) {
return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
- }; |
| Extend a given object with all the properties in passed-in object(s). | _.extend = function(obj) {
+ }; |
| 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) obj[prop] = source[prop];
+ for (var prop in source) {
+ if (source[prop] !== void 0) obj[prop] = source[prop];
+ }
});
return obj;
- }; |
| Fill in a given object with default properties. | _.defaults = function(obj) {
+ }; |
| Fill in a given object with default properties. | _.defaults = function(obj) {
each(slice.call(arguments, 1), function(source) {
- for (var prop in source) if (obj[prop] == null) obj[prop] = source[prop];
+ for (var prop in source) {
+ if (obj[prop] == null) obj[prop] = source[prop];
+ }
});
return obj;
- }; |
| Create a (shallow-cloned) duplicate of an object. | _.clone = function(obj) {
+ }; |
| Create a (shallow-cloned) duplicate of an object. | _.clone = function(obj) {
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
- }; |
| Invokes interceptor with the obj, and then returns obj.
+ }; |
| Invokes interceptor with the obj, and then returns obj.
The primary purpose of this method is to "tap into" a method chain, in
order to perform operations on intermediate results within the chain. | _.tap = function(obj, interceptor) {
interceptor(obj);
return obj;
- }; |
| Perform a deep comparison to check if two objects are equal. | _.isEqual = function(a, b) { |
| Check object identity. | if (a === b) return true; |
| Different types? | var atype = typeof(a), btype = typeof(b);
- if (atype != btype) return false; |
| Basic equality test (watch out for coercions). | |
| One is falsy and the other truthy. | if ((!a && b) || (a && !b)) return false; |
| Unwrap any wrapped objects. | if (a._chain) a = a._wrapped;
- if (b._chain) b = b._wrapped; |
| One of them implements an isEqual()? | if (a.isEqual) return a.isEqual(b); |
| Check dates' integer values. | if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime(); |
| Both are NaN? | if (_.isNaN(a) && _.isNaN(b)) return false; |
| Compare regular expressions. | if (_.isRegExp(a) && _.isRegExp(b))
+ }; |
| Perform a deep comparison to check if two objects are equal. | _.isEqual = function(a, b) { |
| Check object identity. | if (a === b) return true; |
| Different types? | var atype = typeof(a), btype = typeof(b);
+ if (atype != btype) return false; |
| Basic equality test (watch out for coercions). | |
| One is falsy and the other truthy. | if ((!a && b) || (a && !b)) return false; |
| Unwrap any wrapped objects. | if (a._chain) a = a._wrapped;
+ if (b._chain) b = b._wrapped; |
| One of them implements an isEqual()? | if (a.isEqual) return a.isEqual(b); |
| Check dates' integer values. | if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime(); |
| Both are NaN? | if (_.isNaN(a) && _.isNaN(b)) return false; |
| Compare regular expressions. | if (_.isRegExp(a) && _.isRegExp(b))
return a.source === b.source &&
a.global === b.global &&
a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline; |
| If a is not an object by this point, we can't handle it. | if (atype !== 'object') return false; |
| Check for different array lengths before comparing contents. | if (a.length && (a.length !== b.length)) return false; |
| Nothing else worked, deep compare the contents. | var aKeys = _.keys(a), bKeys = _.keys(b); |
| Different object sizes? | if (aKeys.length != bKeys.length) return false; |
| Recursive comparison of contents. | for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
+ a.multiline === b.multiline; |
| If a is not an object by this point, we can't handle it. | if (atype !== 'object') return false; |
| Check for different array lengths before comparing contents. | if (a.length && (a.length !== b.length)) return false; |
| Nothing else worked, deep compare the contents. | var aKeys = _.keys(a), bKeys = _.keys(b); |
| Different object sizes? | if (aKeys.length != bKeys.length) return false; |
| Recursive comparison of contents. | for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
return true;
- }; |
| Is a given array or object empty? | _.isEmpty = function(obj) {
+ }; |
| Is a given array or object empty? | _.isEmpty = function(obj) {
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
return true;
- }; |
| Is a given value a DOM element? | _.isElement = function(obj) {
+ }; |
| Is a given value a DOM element? | _.isElement = function(obj) {
return !!(obj && obj.nodeType == 1);
- }; |
| Is a given value an array?
+ }; |
| Is a given value an array?
Delegates to ECMA5's native Array.isArray | _.isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]';
- }; |
| Is a given variable an arguments object? | _.isArguments = function(obj) {
+ }; |
| Is a given variable an arguments object? | _.isArguments = function(obj) {
return !!(obj && hasOwnProperty.call(obj, 'callee'));
- }; |
| Is a given value a function? | _.isFunction = function(obj) {
+ }; |
| Is a given value a function? | _.isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
- }; |
| Is a given value a string? | _.isString = function(obj) {
+ }; |
| Is a given value a string? | _.isString = function(obj) {
return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
- }; |
| Is a given value a number? | _.isNumber = function(obj) {
+ }; |
| Is a given value a number? | _.isNumber = function(obj) {
return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
- }; |
| Is the given value NaN? NaN happens to be the only value in JavaScript
+ }; |
| Is the given value NaN? NaN happens to be the only value in JavaScript
that does not equal itself. | _.isNaN = function(obj) {
return obj !== obj;
- }; |
| Is a given value a boolean? | _.isBoolean = function(obj) {
+ }; |
| Is a given value a boolean? | _.isBoolean = function(obj) {
return obj === true || obj === false;
- }; |
| Is a given value a date? | _.isDate = function(obj) {
+ }; |
| Is a given value a date? | _.isDate = function(obj) {
return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
- }; |
| Is the given value a regular expression? | _.isRegExp = function(obj) {
+ }; |
| Is the given value a regular expression? | _.isRegExp = function(obj) {
return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
- }; |
| Is a given value equal to null? | _.isNull = function(obj) {
+ }; |
| Is a given value equal to null? | _.isNull = function(obj) {
return obj === null;
- }; |
| Is a given variable undefined? | _.isUndefined = function(obj) {
+ }; |
| 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
+ }; |
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);
- }; |
| 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
- }; |
| JavaScript micro-templating, similar to John Resig's implementation.
+ }; |
| 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;
@@ -452,31 +460,31 @@ and correctly escapes quotes within interpolated code. |
+ "');}return __p.join('');";
var func = new Function('obj', tmpl);
return data ? func(data) : func;
- };
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. | |
| 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. | |
| 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() {
method.apply(this._wrapped, arguments);
return result(this._wrapped, this._chain);
};
- }); |
| 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 215d06a6a..04c878ad0 100644
--- a/index.html
+++ b/index.html
@@ -118,11 +118,11 @@
@@ -160,7 +160,7 @@
bind, bindAll,
memoize, delay, defer,
throttle, debounce,
- once, wrap, compose
+ once, after, wrap, compose
@@ -755,6 +755,22 @@ var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.
+
+
+
+ _.after(count, function)
+
+ Creates a version of the function that will only be run after first
+ being called count times. Useful for grouping asynchronous responses,
+ where you want to be sure that all the async calls have finished, before
+ proceeding.
+
+
+var renderNotes = _.after(notes.length, render);
+_.each(notes, function(note) {
+ note.asyncSave({success: renderNotes});
+});
+// renderNotes is run once, after all notes have saved.
@@ -1227,6 +1243,17 @@ _([1, 2, 3]).value();
Change Log
+
+ — April 18, 2011
+ Added _.after, which will return a function that only runs after
+ first being called a specified number of times.
+ _.invoke can now take a direct function reference.
+ _.every now requires an iterator function to be passed, which
+ mirrors the ECMA5 API.
+ _.extend no longer copies keys when the value is undefined.
+ _.bind now errors when trying to bind an undefined value.
+
+
— Mar 20, 2011
Added an _.defaults function, for use merging together JS objects
diff --git a/package.json b/package.json
index f82099236..86c918592 100644
--- a/package.json
+++ b/package.json
@@ -8,5 +8,5 @@
"dependencies" : [],
"repository" : {"type": "git", "url": "git://github.com/documentcloud/underscore.git"},
"main" : "underscore.js",
- "version" : "1.1.5"
+ "version" : "1.1.6"
}
diff --git a/underscore.js b/underscore.js
index 8d55cc5ce..eaba008c4 100644
--- a/underscore.js
+++ b/underscore.js
@@ -1,4 +1,4 @@
-// Underscore.js 1.1.5
+// Underscore.js 1.1.6
// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
@@ -59,7 +59,7 @@
}
// Current version.
- _.VERSION = '1.1.5';
+ _.VERSION = '1.1.6';
// Collection Functions
// --------------------
|