underscore-source 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
@@ -30,8 +30,15 @@
|
|
30
30
|
// Export the Underscore object for CommonJS.
|
31
31
|
if (typeof exports !== 'undefined') exports._ = _;
|
32
32
|
|
33
|
+
// Create quick reference variables for speed access to core prototypes.
|
34
|
+
var slice = Array.prototype.slice,
|
35
|
+
unshift = Array.prototype.unshift,
|
36
|
+
toString = Object.prototype.toString,
|
37
|
+
hasOwnProperty = Object.prototype.hasOwnProperty,
|
38
|
+
propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
|
39
|
+
|
33
40
|
// Current version.
|
34
|
-
_.VERSION = '0.5.
|
41
|
+
_.VERSION = '0.5.1';
|
35
42
|
|
36
43
|
/*------------------------ Collection Functions: ---------------------------*/
|
37
44
|
|
@@ -42,7 +49,7 @@
|
|
42
49
|
try {
|
43
50
|
if (obj.forEach) {
|
44
51
|
obj.forEach(iterator, context);
|
45
|
-
} else if (obj.
|
52
|
+
} else if (_.isArray(obj) || _.isArguments(obj)) {
|
46
53
|
for (var i=0, l=obj.length; i<l; i++) iterator.call(context, obj[i], i, obj);
|
47
54
|
} else {
|
48
55
|
var keys = _.keys(obj), l = keys.length;
|
@@ -57,7 +64,7 @@
|
|
57
64
|
// Return the results of applying the iterator to each element. Use JavaScript
|
58
65
|
// 1.6's version of map, if possible.
|
59
66
|
_.map = function(obj, iterator, context) {
|
60
|
-
if (obj && obj.map) return obj.map(iterator, context);
|
67
|
+
if (obj && _.isFunction(obj.map)) return obj.map(iterator, context);
|
61
68
|
var results = [];
|
62
69
|
_.each(obj, function(value, index, list) {
|
63
70
|
results.push(iterator.call(context, value, index, list));
|
@@ -68,7 +75,7 @@
|
|
68
75
|
// Reduce builds up a single result from a list of values. Also known as
|
69
76
|
// inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.
|
70
77
|
_.reduce = function(obj, memo, iterator, context) {
|
71
|
-
if (obj && obj.reduce) return obj.reduce(_.bind(iterator, context), memo);
|
78
|
+
if (obj && _.isFunction(obj.reduce)) return obj.reduce(_.bind(iterator, context), memo);
|
72
79
|
_.each(obj, function(value, index, list) {
|
73
80
|
memo = iterator.call(context, memo, value, index, list);
|
74
81
|
});
|
@@ -78,7 +85,7 @@
|
|
78
85
|
// The right-associative version of reduce, also known as foldr. Uses
|
79
86
|
// JavaScript 1.8's version of reduceRight, if available.
|
80
87
|
_.reduceRight = function(obj, memo, iterator, context) {
|
81
|
-
if (obj && obj.reduceRight) return obj.reduceRight(_.bind(iterator, context), memo);
|
88
|
+
if (obj && _.isFunction(obj.reduceRight)) return obj.reduceRight(_.bind(iterator, context), memo);
|
82
89
|
var reversed = _.clone(_.toArray(obj)).reverse();
|
83
90
|
_.each(reversed, function(value, index) {
|
84
91
|
memo = iterator.call(context, memo, value, index, obj);
|
@@ -101,7 +108,7 @@
|
|
101
108
|
// Return all the elements that pass a truth test. Use JavaScript 1.6's
|
102
109
|
// filter(), if it exists.
|
103
110
|
_.select = function(obj, iterator, context) {
|
104
|
-
if (obj.filter) return obj.filter(iterator, context);
|
111
|
+
if (obj && _.isFunction(obj.filter)) return obj.filter(iterator, context);
|
105
112
|
var results = [];
|
106
113
|
_.each(obj, function(value, index, list) {
|
107
114
|
iterator.call(context, value, index, list) && results.push(value);
|
@@ -122,7 +129,7 @@
|
|
122
129
|
// JavaScript 1.6's every(), if it is present.
|
123
130
|
_.all = function(obj, iterator, context) {
|
124
131
|
iterator = iterator || _.identity;
|
125
|
-
if (obj.every) return obj.every(iterator, context);
|
132
|
+
if (obj && _.isFunction(obj.every)) return obj.every(iterator, context);
|
126
133
|
var result = true;
|
127
134
|
_.each(obj, function(value, index, list) {
|
128
135
|
if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
|
@@ -134,7 +141,7 @@
|
|
134
141
|
// JavaScript 1.6's some(), if it exists.
|
135
142
|
_.any = function(obj, iterator, context) {
|
136
143
|
iterator = iterator || _.identity;
|
137
|
-
if (obj.some) return obj.some(iterator, context);
|
144
|
+
if (obj && _.isFunction(obj.some)) return obj.some(iterator, context);
|
138
145
|
var result = false;
|
139
146
|
_.each(obj, function(value, index, list) {
|
140
147
|
if (result = iterator.call(context, value, index, list)) _.breakLoop();
|
@@ -215,9 +222,10 @@
|
|
215
222
|
|
216
223
|
// Convert anything iterable into a real, live array.
|
217
224
|
_.toArray = function(iterable) {
|
218
|
-
if (!iterable)
|
219
|
-
if (iterable.toArray)
|
220
|
-
if (_.isArray(iterable))
|
225
|
+
if (!iterable) return [];
|
226
|
+
if (iterable.toArray) return iterable.toArray();
|
227
|
+
if (_.isArray(iterable)) return iterable;
|
228
|
+
if (_.isArguments(iterable)) return slice.call(iterable);
|
221
229
|
return _.map(iterable, function(val){ return val; });
|
222
230
|
};
|
223
231
|
|
@@ -229,16 +237,18 @@
|
|
229
237
|
/*-------------------------- Array Functions: ------------------------------*/
|
230
238
|
|
231
239
|
// Get the first element of an array. Passing "n" will return the first N
|
232
|
-
// values in the array. Aliased as "head".
|
233
|
-
_.
|
234
|
-
|
240
|
+
// values in the array. Aliased as "head". The "guard" check allows it to work
|
241
|
+
// with _.map.
|
242
|
+
_.first = function(array, n, guard) {
|
243
|
+
return n && !guard ? slice.call(array, 0, n) : array[0];
|
235
244
|
};
|
236
245
|
|
237
246
|
// Returns everything but the first entry of the array. Aliased as "tail".
|
238
247
|
// Especially useful on the arguments object. Passing an "index" will return
|
239
|
-
// the rest of the values in the array from that index onward.
|
240
|
-
|
241
|
-
|
248
|
+
// the rest of the values in the array from that index onward. The "guard"
|
249
|
+
//check allows it to work with _.map.
|
250
|
+
_.rest = function(array, index, guard) {
|
251
|
+
return slice.call(array, _.isUndefined(index) || guard ? 1 : index);
|
242
252
|
};
|
243
253
|
|
244
254
|
// Get the last element of an array.
|
@@ -270,7 +280,7 @@
|
|
270
280
|
// been sorted, you have the option of using a faster algorithm.
|
271
281
|
_.uniq = function(array, isSorted) {
|
272
282
|
return _.reduce(array, [], function(memo, el, i) {
|
273
|
-
if (0 == i || (isSorted ? _.last(memo) != el : !_.include(memo, el))) memo.push(el);
|
283
|
+
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo.push(el);
|
274
284
|
return memo;
|
275
285
|
});
|
276
286
|
};
|
@@ -392,7 +402,7 @@
|
|
392
402
|
_.keys = function(obj) {
|
393
403
|
if(_.isArray(obj)) return _.range(0, obj.length);
|
394
404
|
var keys = [];
|
395
|
-
for (var key in obj) if (
|
405
|
+
for (var key in obj) if (hasOwnProperty.call(obj, key)) keys.push(key);
|
396
406
|
return keys;
|
397
407
|
};
|
398
408
|
|
@@ -401,6 +411,11 @@
|
|
401
411
|
return _.map(obj, _.identity);
|
402
412
|
};
|
403
413
|
|
414
|
+
// Return a sorted list of the function names available in Underscore.
|
415
|
+
_.functions = function(obj) {
|
416
|
+
return _.select(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
|
417
|
+
};
|
418
|
+
|
404
419
|
// Extend a given object with all of the properties in a source object.
|
405
420
|
_.extend = function(destination, source) {
|
406
421
|
for (var property in source) destination[property] = source[property];
|
@@ -422,6 +437,8 @@
|
|
422
437
|
if (atype != btype) return false;
|
423
438
|
// Basic equality test (watch out for coercions).
|
424
439
|
if (a == b) return true;
|
440
|
+
// One is falsy and the other truthy.
|
441
|
+
if ((!a && b) || (a && !b)) return false;
|
425
442
|
// One of them implements an isEqual()?
|
426
443
|
if (a.isEqual) return a.isEqual(b);
|
427
444
|
// Check dates' integer values.
|
@@ -457,6 +474,11 @@
|
|
457
474
|
return !!(obj && obj.nodeType == 1);
|
458
475
|
};
|
459
476
|
|
477
|
+
// Is a given variable an arguments object?
|
478
|
+
_.isArguments = function(obj) {
|
479
|
+
return obj && _.isNumber(obj.length) && !_.isArray(obj) && !propertyIsEnumerable.call(obj, 'length');
|
480
|
+
};
|
481
|
+
|
460
482
|
// Is the given value NaN -- this one is interesting. NaN != NaN, and
|
461
483
|
// isNaN(undefined) == true, so we make sure it's a number first.
|
462
484
|
_.isNaN = function(obj) {
|
@@ -473,13 +495,15 @@
|
|
473
495
|
return typeof obj == 'undefined';
|
474
496
|
};
|
475
497
|
|
476
|
-
// Define the isArray, isDate, isFunction, isNumber, isRegExp, and
|
477
|
-
//
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
498
|
+
// Define the isArray, isDate, isFunction, isNumber, isRegExp, and isString
|
499
|
+
// functions based on their toString identifiers.
|
500
|
+
var types = ['Array', 'Date', 'Function', 'Number', 'RegExp', 'String'];
|
501
|
+
for (var i=0, l=types.length; i<l; i++) {
|
502
|
+
(function() {
|
503
|
+
var identifier = '[object ' + types[i] + ']';
|
504
|
+
_['is' + types[i]] = function(obj) { return toString.call(obj) == identifier; };
|
505
|
+
})();
|
506
|
+
}
|
483
507
|
|
484
508
|
/* -------------------------- Utility Functions: -------------------------- */
|
485
509
|
|
@@ -508,11 +532,6 @@
|
|
508
532
|
return prefix ? prefix + id : id;
|
509
533
|
};
|
510
534
|
|
511
|
-
// Return a sorted list of the function names available in Underscore.
|
512
|
-
_.functions = function(obj) {
|
513
|
-
return _.select(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
|
514
|
-
};
|
515
|
-
|
516
535
|
// JavaScript templating a-la ERB, pilfered from John Resig's
|
517
536
|
// "Secrets of the JavaScript Ninja", page 83.
|
518
537
|
_.template = function(str, data) {
|
@@ -552,24 +571,27 @@
|
|
552
571
|
|
553
572
|
// Add all of the Underscore functions to the wrapper object.
|
554
573
|
_.each(_.functions(_), function(name) {
|
574
|
+
var method = _[name];
|
555
575
|
wrapper.prototype[name] = function() {
|
556
|
-
|
557
|
-
return result(
|
576
|
+
unshift.call(arguments, this._wrapped);
|
577
|
+
return result(method.apply(_, arguments), this._chain);
|
558
578
|
};
|
559
579
|
});
|
560
580
|
|
561
581
|
// Add all mutator Array functions to the wrapper.
|
562
582
|
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
583
|
+
var method = Array.prototype[name];
|
563
584
|
wrapper.prototype[name] = function() {
|
564
|
-
|
585
|
+
method.apply(this._wrapped, arguments);
|
565
586
|
return result(this._wrapped, this._chain);
|
566
587
|
};
|
567
588
|
});
|
568
589
|
|
569
590
|
// Add all accessor Array functions to the wrapper.
|
570
591
|
_.each(['concat', 'join', 'slice'], function(name) {
|
592
|
+
var method = Array.prototype[name];
|
571
593
|
wrapper.prototype[name] = function() {
|
572
|
-
return result(
|
594
|
+
return result(method.apply(this._wrapped, arguments), this._chain);
|
573
595
|
};
|
574
596
|
});
|
575
597
|
|