1 // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc. 2 // Underscore is freely distributable under the MIT license. 3 // Portions of Underscore are inspired or borrowed from Prototype, 4 // Oliver Steele's Functional, and John Resig's Micro-Templating. 5 // For all details and documentation: 6 // http://documentcloud.github.com/underscore 7 8 (function() { 9 10 // Baseline setup 11 // -------------- 12 13 // Establish the root object, `window` in the browser, or `global` on the server. 14 var root = this; 15 16 // Save the previous value of the `_` variable. 17 var previousUnderscore = root._; 18 19 // Establish the object that gets thrown to break out of a loop iteration. 20 var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__'; 21 22 // Save bytes in the minified (but not gzipped) version: 23 var ArrayProto = Array.prototype, ObjProto = Object.prototype; 24 25 // Create quick reference variables for speed access to core prototypes. 26 var slice = ArrayProto.slice, 27 unshift = ArrayProto.unshift, 28 toString = ObjProto.toString, 29 hasOwnProperty = ObjProto.hasOwnProperty; 30 31 // All **ECMAScript 5** native function implementations that we hope to use 32 // are declared here. 33 var 34 nativeForEach = ArrayProto.forEach, 35 nativeMap = ArrayProto.map, 36 nativeReduce = ArrayProto.reduce, 37 nativeReduceRight = ArrayProto.reduceRight, 38 nativeFilter = ArrayProto.filter, 39 nativeEvery = ArrayProto.every, 40 nativeSome = ArrayProto.some, 41 nativeIndexOf = ArrayProto.indexOf, 42 nativeLastIndexOf = ArrayProto.lastIndexOf, 43 nativeIsArray = Array.isArray, 44 nativeKeys = Object.keys; 45 46 // Create a safe reference to the Underscore object for use below. 47 var _ = function(obj) { return new wrapper(obj); }; 48 49 // Export the Underscore object for **CommonJS**. 50 if (typeof exports !== 'undefined') exports._ = _; 51 52 // Export Underscore to the global scope. 53 root._ = _; 54 55 // Current version. 56 _.VERSION = '1.1.2'; 57 58 // Collection Functions 59 // -------------------- 60 61 // The cornerstone, an `each` implementation, aka `forEach`. 62 // Handles objects implementing `forEach`, arrays, and raw objects. 63 // Delegates to **ECMAScript 5**'s native `forEach` if available. 64 var each = _.each = _.forEach = function(obj, iterator, context) { 65 try { 66 if (nativeForEach && obj.forEach === nativeForEach) { 67 obj.forEach(iterator, context); 68 } else if (_.isNumber(obj.length)) { 69 for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj); 70 } else { 71 for (var key in obj) { 72 if (hasOwnProperty.call(obj, key)) iterator.call(context, obj[key], key, obj); 73 } 74 } 75 } catch(e) { 76 if (e != breaker) throw e; 77 } 78 return obj; 79 }; 80 81 // Return the results of applying the iterator to each element. 82 // Delegates to **ECMAScript 5**'s native `map` if available. 83 _.map = function(obj, iterator, context) { 84 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); 85 var results = []; 86 each(obj, function(value, index, list) { 87 results[results.length] = iterator.call(context, value, index, list); 88 }); 89 return results; 90 }; 91 92 // **Reduce** builds up a single result from a list of values, aka `inject`, 93 // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. 94 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { 95 var initial = memo !== void 0; 96 if (nativeReduce && obj.reduce === nativeReduce) { 97 if (context) iterator = _.bind(iterator, context); 98 return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); 99 } 100 each(obj, function(value, index, list) { 101 if (!initial && index === 0) { 102 memo = value; 103 } else { 104 memo = iterator.call(context, memo, value, index, list); 105 } 106 }); 107 return memo; 108 }; 109 110 // The right-associative version of reduce, also known as `foldr`. 111 // Delegates to **ECMAScript 5**'s native `reduceRight` if available. 112 _.reduceRight = _.foldr = function(obj, iterator, memo, context) { 113 if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { 114 if (context) iterator = _.bind(iterator, context); 115 return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); 116 } 117 var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse(); 118 return _.reduce(reversed, iterator, memo, context); 119 }; 120 121 // Return the first value which passes a truth test. Aliased as `detect`. 122 _.find = _.detect = function(obj, iterator, context) { 123 var result; 124 each(obj, function(value, index, list) { 125 if (iterator.call(context, value, index, list)) { 126 result = value; 127 _.breakLoop(); 128 } 129 }); 130 return result; 131 }; 132 133 // Return all the elements that pass a truth test. 134 // Delegates to **ECMAScript 5**'s native `filter` if available. 135 // Aliased as `select`. 136 _.filter = _.select = function(obj, iterator, context) { 137 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); 138 var results = []; 139 each(obj, function(value, index, list) { 140 if (iterator.call(context, value, index, list)) results[results.length] = value; 141 }); 142 return results; 143 }; 144 145 // Return all the elements for which a truth test fails. 146 _.reject = function(obj, iterator, context) { 147 var results = []; 148 each(obj, function(value, index, list) { 149 if (!iterator.call(context, value, index, list)) results[results.length] = value; 150 }); 151 return results; 152 }; 153 154 // Determine whether all of the elements match a truth test. 155 // Delegates to **ECMAScript 5**'s native `every` if available. 156 // Aliased as `all`. 157 _.every = _.all = function(obj, iterator, context) { 158 iterator = iterator || _.identity; 159 if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); 160 var result = true; 161 each(obj, function(value, index, list) { 162 if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop(); 163 }); 164 return result; 165 }; 166 167 // Determine if at least one element in the object matches a truth test. 168 // Delegates to **ECMAScript 5**'s native `some` if available. 169 // Aliased as `any`. 170 _.some = _.any = function(obj, iterator, context) { 171 iterator = iterator || _.identity; 172 if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); 173 var result = false; 174 each(obj, function(value, index, list) { 175 if (result = iterator.call(context, value, index, list)) _.breakLoop(); 176 }); 177 return result; 178 }; 179 180 // Determine if a given value is included in the array or object using `===`. 181 // Aliased as `contains`. 182 _.include = _.contains = function(obj, target) { 183 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; 184 var found = false; 185 each(obj, function(value) { 186 if (found = value === target) _.breakLoop(); 187 }); 188 return found; 189 }; 190 191 // Invoke a method (with arguments) on every item in a collection. 192 _.invoke = function(obj, method) { 193 var args = slice.call(arguments, 2); 194 return _.map(obj, function(value) { 195 return (method ? value[method] : value).apply(value, args); 196 }); 197 }; 198 199 // Convenience version of a common use case of `map`: fetching a property. 200 _.pluck = function(obj, key) { 201 return _.map(obj, function(value){ return value[key]; }); 202 }; 203 204 // Return the maximum element or (element-based computation). 205 _.max = function(obj, iterator, context) { 206 if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); 207 var result = {computed : -Infinity}; 208 each(obj, function(value, index, list) { 209 var computed = iterator ? iterator.call(context, value, index, list) : value; 210 computed >= result.computed && (result = {value : value, computed : computed}); 211 }); 212 return result.value; 213 }; 214 215 // Return the minimum element (or element-based computation). 216 _.min = function(obj, iterator, context) { 217 if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); 218 var result = {computed : Infinity}; 219 each(obj, function(value, index, list) { 220 var computed = iterator ? iterator.call(context, value, index, list) : value; 221 computed < result.computed && (result = {value : value, computed : computed}); 222 }); 223 return result.value; 224 }; 225 226 // Sort the object's values by a criterion produced by an iterator. 227 _.sortBy = function(obj, iterator, context) { 228 return _.pluck(_.map(obj, function(value, index, list) { 229 return { 230 value : value, 231 criteria : iterator.call(context, value, index, list) 232 }; 233 }).sort(function(left, right) { 234 var a = left.criteria, b = right.criteria; 235 return a < b ? -1 : a > b ? 1 : 0; 236 }), 'value'); 237 }; 238 239 // Use a comparator function to figure out at what index an object should 240 // be inserted so as to maintain order. Uses binary search. 241 _.sortedIndex = function(array, obj, iterator) { 242 iterator = iterator || _.identity; 243 var low = 0, high = array.length; 244 while (low < high) { 245 var mid = (low + high) >> 1; 246 iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; 247 } 248 return low; 249 }; 250 251 // Safely convert anything iterable into a real, live array. 252 _.toArray = function(iterable) { 253 if (!iterable) return []; 254 if (iterable.toArray) return iterable.toArray(); 255 if (_.isArray(iterable)) return iterable; 256 if (_.isArguments(iterable)) return slice.call(iterable); 257 return _.values(iterable); 258 }; 259 260 // Return the number of elements in an object. 261 _.size = function(obj) { 262 return _.toArray(obj).length; 263 }; 264 265 // Array Functions 266 // --------------- 267 268 // Get the first element of an array. Passing **n** will return the first N 269 // values in the array. Aliased as `head`. The **guard** check allows it to work 270 // with `_.map`. 271 _.first = _.head = function(array, n, guard) { 272 return n && !guard ? slice.call(array, 0, n) : array[0]; 273 }; 274 275 // Returns everything but the first entry of the array. Aliased as `tail`. 276 // Especially useful on the arguments object. Passing an **index** will return 277 // the rest of the values in the array from that index onward. The **guard** 278 // check allows it to work with `_.map`. 279 _.rest = _.tail = function(array, index, guard) { 280 return slice.call(array, _.isUndefined(index) || guard ? 1 : index); 281 }; 282 283 // Get the last element of an array. 284 _.last = function(array) { 285 return array[array.length - 1]; 286 }; 287 288 // Trim out all falsy values from an array. 289 _.compact = function(array) { 290 return _.filter(array, function(value){ return !!value; }); 291 }; 292 293 // Return a completely flattened version of an array. 294 _.flatten = function(array) { 295 return _.reduce(array, function(memo, value) { 296 if (_.isArray(value)) return memo.concat(_.flatten(value)); 297 memo[memo.length] = value; 298 return memo; 299 }, []); 300 }; 301 302 // Return a version of the array that does not contain the specified value(s). 303 _.without = function(array) { 304 var values = slice.call(arguments, 1); 305 return _.filter(array, function(value){ return !_.include(values, value); }); 306 }; 307 308 // Produce a duplicate-free version of the array. If the array has already 309 // been sorted, you have the option of using a faster algorithm. 310 // Aliased as `unique`. 311 _.uniq = _.unique = function(array, isSorted) { 312 return _.reduce(array, function(memo, el, i) { 313 if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el; 314 return memo; 315 }, []); 316 }; 317 318 // Produce an array that contains every item shared between all the 319 // passed-in arrays. 320 _.intersect = function(array) { 321 var rest = slice.call(arguments, 1); 322 return _.filter(_.uniq(array), function(item) { 323 return _.every(rest, function(other) { 324 return _.indexOf(other, item) >= 0; 325 }); 326 }); 327 }; 328 329 // Zip together multiple lists into a single array -- elements that share 330 // an index go together. 331 _.zip = function() { 332 var args = slice.call(arguments); 333 var length = _.max(_.pluck(args, 'length')); 334 var results = new Array(length); 335 for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); 336 return results; 337 }; 338 339 // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), 340 // we need this function. Return the position of the first occurence of an 341 // item in an array, or -1 if the item is not included in the array. 342 // Delegates to **ECMAScript 5**'s native `indexOf` if available. 343 _.indexOf = function(array, item) { 344 if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); 345 for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; 346 return -1; 347 }; 348 349 350 // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. 351 _.lastIndexOf = function(array, item) { 352 if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); 353 var i = array.length; 354 while (i--) if (array[i] === item) return i; 355 return -1; 356 }; 357 358 // Generate an integer Array containing an arithmetic progression. A port of 359 // the native Python `range()` function. See 360 // [the Python documentation](http://docs.python.org/library/functions.html#range). 361 _.range = function(start, stop, step) { 362 var args = slice.call(arguments), 363 solo = args.length <= 1, 364 start = solo ? 0 : args[0], 365 stop = solo ? args[0] : args[1], 366 step = args[2] || 1, 367 len = Math.max(Math.ceil((stop - start) / step), 0), 368 idx = 0, 369 range = new Array(len); 370 while (idx < len) { 371 range[idx++] = start; 372 start += step; 373 } 374 return range; 375 }; 376 377 // Function (ahem) Functions 378 // ------------------ 379 380 // Create a function bound to a given object (assigning `this`, and arguments, 381 // optionally). Binding with arguments is also known as `curry`. 382 _.bind = function(func, obj) { 383 var args = slice.call(arguments, 2); 384 return function() { 385 return func.apply(obj || {}, args.concat(slice.call(arguments))); 386 }; 387 }; 388 389 // Bind all of an object's methods to that object. Useful for ensuring that 390 // all callbacks defined on an object belong to it. 391 _.bindAll = function(obj) { 392 var funcs = slice.call(arguments, 1); 393 if (funcs.length == 0) funcs = _.functions(obj); 394 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); 395 return obj; 396 }; 397 398 // Memoize an expensive function by storing its results. 399 _.memoize = function(func, hasher) { 400 var memo = {}; 401 hasher = hasher || _.identity; 402 return function() { 403 var key = hasher.apply(this, arguments); 404 return key in memo ? memo[key] : (memo[key] = func.apply(this, arguments)); 405 }; 406 }; 407 408 // Delays a function for the given number of milliseconds, and then calls 409 // it with the arguments supplied. 410 _.delay = function(func, wait) { 411 var args = slice.call(arguments, 2); 412 return setTimeout(function(){ return func.apply(func, args); }, wait); 413 }; 414 415 // Defers a function, scheduling it to run after the current call stack has 416 // cleared. 417 _.defer = function(func) { 418 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); 419 }; 420 421 // Returns the first function passed as an argument to the second, 422 // allowing you to adjust arguments, run code before and after, and 423 // conditionally execute the original function. 424 _.wrap = function(func, wrapper) { 425 return function() { 426 var args = [func].concat(slice.call(arguments)); 427 return wrapper.apply(wrapper, args); 428 }; 429 }; 430 431 // Returns a function that is the composition of a list of functions, each 432 // consuming the return value of the function that follows. 433 _.compose = function() { 434 var funcs = slice.call(arguments); 435 return function() { 436 var args = slice.call(arguments); 437 for (var i=funcs.length-1; i >= 0; i--) { 438 args = [funcs[i].apply(this, args)]; 439 } 440 return args[0]; 441 }; 442 }; 443 444 // Object Functions 445 // ---------------- 446 447 // Retrieve the names of an object's properties. 448 // Delegates to **ECMAScript 5**'s native `Object.keys` 449 _.keys = nativeKeys || function(obj) { 450 if (_.isArray(obj)) return _.range(0, obj.length); 451 var keys = []; 452 for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key; 453 return keys; 454 }; 455 456 // Retrieve the values of an object's properties. 457 _.values = function(obj) { 458 return _.map(obj, _.identity); 459 }; 460 461 // Return a sorted list of the function names available on the object. 462 // Aliased as `methods` 463 _.functions = _.methods = function(obj) { 464 return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort(); 465 }; 466 467 // Extend a given object with all the properties in passed-in object(s). 468 _.extend = function(obj) { 469 each(slice.call(arguments, 1), function(source) { 470 for (var prop in source) obj[prop] = source[prop]; 471 }); 472 return obj; 473 }; 474 475 // Create a (shallow-cloned) duplicate of an object. 476 _.clone = function(obj) { 477 return _.isArray(obj) ? obj.slice() : _.extend({}, obj); 478 }; 479 480 // Invokes interceptor with the obj, and then returns obj. 481 // The primary purpose of this method is to "tap into" a method chain, in 482 // order to perform operations on intermediate results within the chain. 483 _.tap = function(obj, interceptor) { 484 interceptor(obj); 485 return obj; 486 }; 487 488 // Perform a deep comparison to check if two objects are equal. 489 _.isEqual = function(a, b) { 490 // Check object identity. 491 if (a === b) return true; 492 // Different types? 493 var atype = typeof(a), btype = typeof(b); 494 if (atype != btype) return false; 495 // Basic equality test (watch out for coercions). 496 if (a == b) return true; 497 // One is falsy and the other truthy. 498 if ((!a && b) || (a && !b)) return false; 499 // One of them implements an isEqual()? 500 if (a.isEqual) return a.isEqual(b); 501 // Check dates' integer values. 502 if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime(); 503 // Both are NaN? 504 if (_.isNaN(a) && _.isNaN(b)) return false; 505 // Compare regular expressions. 506 if (_.isRegExp(a) && _.isRegExp(b)) 507 return a.source === b.source && 508 a.global === b.global && 509 a.ignoreCase === b.ignoreCase && 510 a.multiline === b.multiline; 511 // If a is not an object by this point, we can't handle it. 512 if (atype !== 'object') return false; 513 // Check for different array lengths before comparing contents. 514 if (a.length && (a.length !== b.length)) return false; 515 // Nothing else worked, deep compare the contents. 516 var aKeys = _.keys(a), bKeys = _.keys(b); 517 // Different object sizes? 518 if (aKeys.length != bKeys.length) return false; 519 // Recursive comparison of contents. 520 for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false; 521 return true; 522 }; 523 524 // Is a given array or object empty? 525 _.isEmpty = function(obj) { 526 if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; 527 for (var key in obj) if (hasOwnProperty.call(obj, key)) return false; 528 return true; 529 }; 530 531 // Is a given value a DOM element? 532 _.isElement = function(obj) { 533 return !!(obj && obj.nodeType == 1); 534 }; 535 536 // Is a given value an array? 537 // Delegates to ECMA5's native Array.isArray 538 _.isArray = nativeIsArray || function(obj) { 539 return !!(obj && obj.concat && obj.unshift && !obj.callee); 540 }; 541 542 // Is a given variable an arguments object? 543 _.isArguments = function(obj) { 544 return !!(obj && obj.callee); 545 }; 546 547 // Is a given value a function? 548 _.isFunction = function(obj) { 549 return !!(obj && obj.constructor && obj.call && obj.apply); 550 }; 551 552 // Is a given value a string? 553 _.isString = function(obj) { 554 return !!(obj === '' || (obj && obj.charCodeAt && obj.substr)); 555 }; 556 557 // Is a given value a number? 558 _.isNumber = function(obj) { 559 return (obj === +obj) || (toString.call(obj) === '[object Number]'); 560 }; 561 562 // Is a given value a boolean? 563 _.isBoolean = function(obj) { 564 return obj === true || obj === false; 565 }; 566 567 // Is a given value a date? 568 _.isDate = function(obj) { 569 return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear); 570 }; 571 572 // Is the given value a regular expression? 573 _.isRegExp = function(obj) { 574 return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false)); 575 }; 576 577 // Is the given value NaN -- this one is interesting. NaN != NaN, and 578 // isNaN(undefined) == true, so we make sure it's a number first. 579 _.isNaN = function(obj) { 580 return _.isNumber(obj) && isNaN(obj); 581 }; 582 583 // Is a given value equal to null? 584 _.isNull = function(obj) { 585 return obj === null; 586 }; 587 588 // Is a given variable undefined? 589 _.isUndefined = function(obj) { 590 return typeof obj == 'undefined'; 591 }; 592 593 // Utility Functions 594 // ----------------- 595 596 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its 597 // previous owner. Returns a reference to the Underscore object. 598 _.noConflict = function() { 599 root._ = previousUnderscore; 600 return this; 601 }; 602 603 // Keep the identity function around for default iterators. 604 _.identity = function(value) { 605 return value; 606 }; 607 608 // Run a function **n** times. 609 _.times = function (n, iterator, context) { 610 for (var i = 0; i < n; i++) iterator.call(context, i); 611 }; 612 613 // Break out of the middle of an iteration. 614 _.breakLoop = function() { 615 throw breaker; 616 }; 617 618 // Add your own custom functions to the Underscore object, ensuring that 619 // they're correctly added to the OOP wrapper as well. 620 _.mixin = function(obj) { 621 each(_.functions(obj), function(name){ 622 addToWrapper(name, _[name] = obj[name]); 623 }); 624 }; 625 626 // Generate a unique integer id (unique within the entire client session). 627 // Useful for temporary DOM ids. 628 var idCounter = 0; 629 _.uniqueId = function(prefix) { 630 var id = idCounter++; 631 return prefix ? prefix + id : id; 632 }; 633 634 // By default, Underscore uses ERB-style template delimiters, change the 635 // following template settings to use alternative delimiters. 636 _.templateSettings = { 637 evaluate : /<%([\s\S]+?)%>/g, 638 interpolate : /<%=([\s\S]+?)%>/g 639 }; 640 641 // JavaScript micro-templating, similar to John Resig's implementation. 642 // Underscore templating handles arbitrary delimiters, preserves whitespace, 643 // and correctly escapes quotes within interpolated code. 644 _.template = function(str, data) { 645 var c = _.templateSettings; 646 var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + 647 'with(obj||{}){__p.push(\'' + 648 str.replace(/'/g, "\\'") 649 .replace(c.interpolate, function(match, code) { 650 return "'," + code.replace(/\\'/g, "'") + ",'"; 651 }) 652 .replace(c.evaluate || null, function(match, code) { 653 return "');" + code.replace(/\\'/g, "'") 654 .replace(/[\r\n\t]/g, ' ') + "__p.push('"; 655 }) 656 .replace(/\r/g, '\\r') 657 .replace(/\n/g, '\\n') 658 .replace(/\t/g, '\\t') 659 + "');}return __p.join('');"; 660 var func = new Function('obj', tmpl); 661 return data ? func(data) : func; 662 }; 663 664 // The OOP Wrapper 665 // --------------- 666 667 // If Underscore is called as a function, it returns a wrapped object that 668 // can be used OO-style. This wrapper holds altered versions of all the 669 // underscore functions. Wrapped objects may be chained. 670 var wrapper = function(obj) { this._wrapped = obj; }; 671 672 // Expose `wrapper.prototype` as `_.prototype` 673 _.prototype = wrapper.prototype; 674 675 // Helper function to continue chaining intermediate results. 676 var result = function(obj, chain) { 677 return chain ? _(obj).chain() : obj; 678 }; 679 680 // A method to easily add functions to the OOP wrapper. 681 var addToWrapper = function(name, func) { 682 wrapper.prototype[name] = function() { 683 var args = slice.call(arguments); 684 unshift.call(args, this._wrapped); 685 return result(func.apply(_, args), this._chain); 686 }; 687 }; 688 689 // Add all of the Underscore functions to the wrapper object. 690 _.mixin(_); 691 692 // Add all mutator Array functions to the wrapper. 693 each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { 694 var method = ArrayProto[name]; 695 wrapper.prototype[name] = function() { 696 method.apply(this._wrapped, arguments); 697 return result(this._wrapped, this._chain); 698 }; 699 }); 700 701 // Add all accessor Array functions to the wrapper. 702 each(['concat', 'join', 'slice'], function(name) { 703 var method = ArrayProto[name]; 704 wrapper.prototype[name] = function() { 705 return result(method.apply(this._wrapped, arguments), this._chain); 706 }; 707 }); 708 709 // Start chaining a wrapped Underscore object. 710 wrapper.prototype.chain = function() { 711 this._chain = true; 712 return this; 713 }; 714 715 // Extracts the result from a wrapped and chained object. 716 wrapper.prototype.value = function() { 717 return this._wrapped; 718 }; 719 720 })(); 721