underscore-rails 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/underscore-rails/version.rb +1 -1
- data/vendor/assets/javascripts/underscore.js +497 -424
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5576b859213b27f6b5e4d9dda4cf59e7be14d389
|
4
|
+
data.tar.gz: 773709d74cc092353d7ef8ba8ac1e292e3136cce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19b35afc5770a487bcb3ee1ae373df73d76b4167c2178248681df3a07efb7a86c6ae0c6b36f1fadb951343254a36f3e208fb8165b8c41da224025ed1d93215b6
|
7
|
+
data.tar.gz: f0bb8b1354a3fabe86a0387098b512f123b1f66aecd2d583cdb15c0b94160777a7c5629fc5dc664b73e4c2f393295e29d914fdde69757fc1a66014f74d122c9a
|
@@ -1,4 +1,4 @@
|
|
1
|
-
// Underscore.js 1.
|
1
|
+
// Underscore.js 1.7.0
|
2
2
|
// http://underscorejs.org
|
3
3
|
// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
4
4
|
// Underscore may be freely distributed under the MIT license.
|
@@ -14,9 +14,6 @@
|
|
14
14
|
// Save the previous value of the `_` variable.
|
15
15
|
var previousUnderscore = root._;
|
16
16
|
|
17
|
-
// Establish the object that gets returned to break out of a loop iteration.
|
18
|
-
var breaker = {};
|
19
|
-
|
20
17
|
// Save bytes in the minified (but not gzipped) version:
|
21
18
|
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
22
19
|
|
@@ -31,15 +28,6 @@
|
|
31
28
|
// All **ECMAScript 5** native function implementations that we hope to use
|
32
29
|
// are declared here.
|
33
30
|
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
31
|
nativeIsArray = Array.isArray,
|
44
32
|
nativeKeys = Object.keys,
|
45
33
|
nativeBind = FuncProto.bind;
|
@@ -53,8 +41,7 @@
|
|
53
41
|
|
54
42
|
// Export the Underscore object for **Node.js**, with
|
55
43
|
// backwards-compatibility for the old `require()` API. If we're in
|
56
|
-
// the browser, add `_` as a global object
|
57
|
-
// for Closure Compiler "advanced" mode.
|
44
|
+
// the browser, add `_` as a global object.
|
58
45
|
if (typeof exports !== 'undefined') {
|
59
46
|
if (typeof module !== 'undefined' && module.exports) {
|
60
47
|
exports = module.exports = _;
|
@@ -65,98 +52,125 @@
|
|
65
52
|
}
|
66
53
|
|
67
54
|
// Current version.
|
68
|
-
_.VERSION = '1.
|
55
|
+
_.VERSION = '1.7.0';
|
56
|
+
|
57
|
+
// Internal function that returns an efficient (for current engines) version
|
58
|
+
// of the passed-in callback, to be repeatedly applied in other Underscore
|
59
|
+
// functions.
|
60
|
+
var createCallback = function(func, context, argCount) {
|
61
|
+
if (context === void 0) return func;
|
62
|
+
switch (argCount == null ? 3 : argCount) {
|
63
|
+
case 1: return function(value) {
|
64
|
+
return func.call(context, value);
|
65
|
+
};
|
66
|
+
case 2: return function(value, other) {
|
67
|
+
return func.call(context, value, other);
|
68
|
+
};
|
69
|
+
case 3: return function(value, index, collection) {
|
70
|
+
return func.call(context, value, index, collection);
|
71
|
+
};
|
72
|
+
case 4: return function(accumulator, value, index, collection) {
|
73
|
+
return func.call(context, accumulator, value, index, collection);
|
74
|
+
};
|
75
|
+
}
|
76
|
+
return function() {
|
77
|
+
return func.apply(context, arguments);
|
78
|
+
};
|
79
|
+
};
|
80
|
+
|
81
|
+
// A mostly-internal function to generate callbacks that can be applied
|
82
|
+
// to each element in a collection, returning the desired result — either
|
83
|
+
// identity, an arbitrary callback, a property matcher, or a property accessor.
|
84
|
+
_.iteratee = function(value, context, argCount) {
|
85
|
+
if (value == null) return _.identity;
|
86
|
+
if (_.isFunction(value)) return createCallback(value, context, argCount);
|
87
|
+
if (_.isObject(value)) return _.matches(value);
|
88
|
+
return _.property(value);
|
89
|
+
};
|
69
90
|
|
70
91
|
// Collection Functions
|
71
92
|
// --------------------
|
72
93
|
|
73
94
|
// The cornerstone, an `each` implementation, aka `forEach`.
|
74
|
-
// Handles objects
|
75
|
-
//
|
76
|
-
|
95
|
+
// Handles raw objects in addition to array-likes. Treats all
|
96
|
+
// sparse array-likes as if they were dense.
|
97
|
+
_.each = _.forEach = function(obj, iteratee, context) {
|
77
98
|
if (obj == null) return obj;
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
for (
|
82
|
-
|
99
|
+
iteratee = createCallback(iteratee, context);
|
100
|
+
var i, length = obj.length;
|
101
|
+
if (length === +length) {
|
102
|
+
for (i = 0; i < length; i++) {
|
103
|
+
iteratee(obj[i], i, obj);
|
83
104
|
}
|
84
105
|
} else {
|
85
106
|
var keys = _.keys(obj);
|
86
|
-
for (
|
87
|
-
|
107
|
+
for (i = 0, length = keys.length; i < length; i++) {
|
108
|
+
iteratee(obj[keys[i]], keys[i], obj);
|
88
109
|
}
|
89
110
|
}
|
90
111
|
return obj;
|
91
112
|
};
|
92
113
|
|
93
|
-
// Return the results of applying the
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
114
|
+
// Return the results of applying the iteratee to each element.
|
115
|
+
_.map = _.collect = function(obj, iteratee, context) {
|
116
|
+
if (obj == null) return [];
|
117
|
+
iteratee = _.iteratee(iteratee, context);
|
118
|
+
var keys = obj.length !== +obj.length && _.keys(obj),
|
119
|
+
length = (keys || obj).length,
|
120
|
+
results = Array(length),
|
121
|
+
currentKey;
|
122
|
+
for (var index = 0; index < length; index++) {
|
123
|
+
currentKey = keys ? keys[index] : index;
|
124
|
+
results[index] = iteratee(obj[currentKey], currentKey, obj);
|
125
|
+
}
|
102
126
|
return results;
|
103
127
|
};
|
104
128
|
|
105
129
|
var reduceError = 'Reduce of empty array with no initial value';
|
106
130
|
|
107
131
|
// **Reduce** builds up a single result from a list of values, aka `inject`,
|
108
|
-
// or `foldl`.
|
109
|
-
_.reduce = _.foldl = _.inject = function(obj,
|
110
|
-
var initial = arguments.length > 2;
|
132
|
+
// or `foldl`.
|
133
|
+
_.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
|
111
134
|
if (obj == null) obj = [];
|
112
|
-
|
113
|
-
|
114
|
-
|
135
|
+
iteratee = createCallback(iteratee, context, 4);
|
136
|
+
var keys = obj.length !== +obj.length && _.keys(obj),
|
137
|
+
length = (keys || obj).length,
|
138
|
+
index = 0, currentKey;
|
139
|
+
if (arguments.length < 3) {
|
140
|
+
if (!length) throw new TypeError(reduceError);
|
141
|
+
memo = obj[keys ? keys[index++] : index++];
|
142
|
+
}
|
143
|
+
for (; index < length; index++) {
|
144
|
+
currentKey = keys ? keys[index] : index;
|
145
|
+
memo = iteratee(memo, obj[currentKey], currentKey, obj);
|
115
146
|
}
|
116
|
-
each(obj, function(value, index, list) {
|
117
|
-
if (!initial) {
|
118
|
-
memo = value;
|
119
|
-
initial = true;
|
120
|
-
} else {
|
121
|
-
memo = iterator.call(context, memo, value, index, list);
|
122
|
-
}
|
123
|
-
});
|
124
|
-
if (!initial) throw new TypeError(reduceError);
|
125
147
|
return memo;
|
126
148
|
};
|
127
149
|
|
128
150
|
// The right-associative version of reduce, also known as `foldr`.
|
129
|
-
|
130
|
-
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
131
|
-
var initial = arguments.length > 2;
|
151
|
+
_.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
|
132
152
|
if (obj == null) obj = [];
|
133
|
-
|
134
|
-
|
135
|
-
|
153
|
+
iteratee = createCallback(iteratee, context, 4);
|
154
|
+
var keys = obj.length !== + obj.length && _.keys(obj),
|
155
|
+
index = (keys || obj).length,
|
156
|
+
currentKey;
|
157
|
+
if (arguments.length < 3) {
|
158
|
+
if (!index) throw new TypeError(reduceError);
|
159
|
+
memo = obj[keys ? keys[--index] : --index];
|
136
160
|
}
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
length = keys.length;
|
161
|
+
while (index--) {
|
162
|
+
currentKey = keys ? keys[index] : index;
|
163
|
+
memo = iteratee(memo, obj[currentKey], currentKey, obj);
|
141
164
|
}
|
142
|
-
each(obj, function(value, index, list) {
|
143
|
-
index = keys ? keys[--length] : --length;
|
144
|
-
if (!initial) {
|
145
|
-
memo = obj[index];
|
146
|
-
initial = true;
|
147
|
-
} else {
|
148
|
-
memo = iterator.call(context, memo, obj[index], index, list);
|
149
|
-
}
|
150
|
-
});
|
151
|
-
if (!initial) throw new TypeError(reduceError);
|
152
165
|
return memo;
|
153
166
|
};
|
154
167
|
|
155
168
|
// Return the first value which passes a truth test. Aliased as `detect`.
|
156
169
|
_.find = _.detect = function(obj, predicate, context) {
|
157
170
|
var result;
|
158
|
-
|
159
|
-
|
171
|
+
predicate = _.iteratee(predicate, context);
|
172
|
+
_.some(obj, function(value, index, list) {
|
173
|
+
if (predicate(value, index, list)) {
|
160
174
|
result = value;
|
161
175
|
return true;
|
162
176
|
}
|
@@ -165,61 +179,58 @@
|
|
165
179
|
};
|
166
180
|
|
167
181
|
// Return all the elements that pass a truth test.
|
168
|
-
// Delegates to **ECMAScript 5**'s native `filter` if available.
|
169
182
|
// Aliased as `select`.
|
170
183
|
_.filter = _.select = function(obj, predicate, context) {
|
171
184
|
var results = [];
|
172
185
|
if (obj == null) return results;
|
173
|
-
|
174
|
-
each(obj, function(value, index, list) {
|
175
|
-
if (predicate
|
186
|
+
predicate = _.iteratee(predicate, context);
|
187
|
+
_.each(obj, function(value, index, list) {
|
188
|
+
if (predicate(value, index, list)) results.push(value);
|
176
189
|
});
|
177
190
|
return results;
|
178
191
|
};
|
179
192
|
|
180
193
|
// Return all the elements for which a truth test fails.
|
181
194
|
_.reject = function(obj, predicate, context) {
|
182
|
-
return _.filter(obj,
|
183
|
-
return !predicate.call(context, value, index, list);
|
184
|
-
}, context);
|
195
|
+
return _.filter(obj, _.negate(_.iteratee(predicate)), context);
|
185
196
|
};
|
186
197
|
|
187
198
|
// Determine whether all of the elements match a truth test.
|
188
|
-
// Delegates to **ECMAScript 5**'s native `every` if available.
|
189
199
|
// Aliased as `all`.
|
190
200
|
_.every = _.all = function(obj, predicate, context) {
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
201
|
+
if (obj == null) return true;
|
202
|
+
predicate = _.iteratee(predicate, context);
|
203
|
+
var keys = obj.length !== +obj.length && _.keys(obj),
|
204
|
+
length = (keys || obj).length,
|
205
|
+
index, currentKey;
|
206
|
+
for (index = 0; index < length; index++) {
|
207
|
+
currentKey = keys ? keys[index] : index;
|
208
|
+
if (!predicate(obj[currentKey], currentKey, obj)) return false;
|
209
|
+
}
|
210
|
+
return true;
|
199
211
|
};
|
200
212
|
|
201
213
|
// Determine if at least one element in the object matches a truth test.
|
202
|
-
// Delegates to **ECMAScript 5**'s native `some` if available.
|
203
214
|
// Aliased as `any`.
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
215
|
+
_.some = _.any = function(obj, predicate, context) {
|
216
|
+
if (obj == null) return false;
|
217
|
+
predicate = _.iteratee(predicate, context);
|
218
|
+
var keys = obj.length !== +obj.length && _.keys(obj),
|
219
|
+
length = (keys || obj).length,
|
220
|
+
index, currentKey;
|
221
|
+
for (index = 0; index < length; index++) {
|
222
|
+
currentKey = keys ? keys[index] : index;
|
223
|
+
if (predicate(obj[currentKey], currentKey, obj)) return true;
|
224
|
+
}
|
225
|
+
return false;
|
213
226
|
};
|
214
227
|
|
215
228
|
// Determine if the array or object contains a given value (using `===`).
|
216
229
|
// Aliased as `include`.
|
217
230
|
_.contains = _.include = function(obj, target) {
|
218
231
|
if (obj == null) return false;
|
219
|
-
if (
|
220
|
-
return
|
221
|
-
return value === target;
|
222
|
-
});
|
232
|
+
if (obj.length !== +obj.length) obj = _.values(obj);
|
233
|
+
return _.indexOf(obj, target) >= 0;
|
223
234
|
};
|
224
235
|
|
225
236
|
// Invoke a method (with arguments) on every item in a collection.
|
@@ -248,51 +259,67 @@
|
|
248
259
|
return _.find(obj, _.matches(attrs));
|
249
260
|
};
|
250
261
|
|
251
|
-
// Return the maximum element or
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
if (
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
result = value;
|
263
|
-
lastComputed = computed;
|
262
|
+
// Return the maximum element (or element-based computation).
|
263
|
+
_.max = function(obj, iteratee, context) {
|
264
|
+
var result = -Infinity, lastComputed = -Infinity,
|
265
|
+
value, computed;
|
266
|
+
if (iteratee == null && obj != null) {
|
267
|
+
obj = obj.length === +obj.length ? obj : _.values(obj);
|
268
|
+
for (var i = 0, length = obj.length; i < length; i++) {
|
269
|
+
value = obj[i];
|
270
|
+
if (value > result) {
|
271
|
+
result = value;
|
272
|
+
}
|
264
273
|
}
|
265
|
-
}
|
274
|
+
} else {
|
275
|
+
iteratee = _.iteratee(iteratee, context);
|
276
|
+
_.each(obj, function(value, index, list) {
|
277
|
+
computed = iteratee(value, index, list);
|
278
|
+
if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
|
279
|
+
result = value;
|
280
|
+
lastComputed = computed;
|
281
|
+
}
|
282
|
+
});
|
283
|
+
}
|
266
284
|
return result;
|
267
285
|
};
|
268
286
|
|
269
287
|
// Return the minimum element (or element-based computation).
|
270
|
-
_.min = function(obj,
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
288
|
+
_.min = function(obj, iteratee, context) {
|
289
|
+
var result = Infinity, lastComputed = Infinity,
|
290
|
+
value, computed;
|
291
|
+
if (iteratee == null && obj != null) {
|
292
|
+
obj = obj.length === +obj.length ? obj : _.values(obj);
|
293
|
+
for (var i = 0, length = obj.length; i < length; i++) {
|
294
|
+
value = obj[i];
|
295
|
+
if (value < result) {
|
296
|
+
result = value;
|
297
|
+
}
|
280
298
|
}
|
281
|
-
}
|
299
|
+
} else {
|
300
|
+
iteratee = _.iteratee(iteratee, context);
|
301
|
+
_.each(obj, function(value, index, list) {
|
302
|
+
computed = iteratee(value, index, list);
|
303
|
+
if (computed < lastComputed || computed === Infinity && result === Infinity) {
|
304
|
+
result = value;
|
305
|
+
lastComputed = computed;
|
306
|
+
}
|
307
|
+
});
|
308
|
+
}
|
282
309
|
return result;
|
283
310
|
};
|
284
311
|
|
285
|
-
// Shuffle
|
312
|
+
// Shuffle a collection, using the modern version of the
|
286
313
|
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
|
287
314
|
_.shuffle = function(obj) {
|
288
|
-
var
|
289
|
-
var
|
290
|
-
var shuffled =
|
291
|
-
|
292
|
-
rand = _.random(index
|
293
|
-
shuffled[index
|
294
|
-
shuffled[rand] =
|
295
|
-
}
|
315
|
+
var set = obj && obj.length === +obj.length ? obj : _.values(obj);
|
316
|
+
var length = set.length;
|
317
|
+
var shuffled = Array(length);
|
318
|
+
for (var index = 0, rand; index < length; index++) {
|
319
|
+
rand = _.random(0, index);
|
320
|
+
if (rand !== index) shuffled[index] = shuffled[rand];
|
321
|
+
shuffled[rand] = set[index];
|
322
|
+
}
|
296
323
|
return shuffled;
|
297
324
|
};
|
298
325
|
|
@@ -307,21 +334,14 @@
|
|
307
334
|
return _.shuffle(obj).slice(0, Math.max(0, n));
|
308
335
|
};
|
309
336
|
|
310
|
-
//
|
311
|
-
|
312
|
-
|
313
|
-
if (_.isFunction(value)) return value;
|
314
|
-
return _.property(value);
|
315
|
-
};
|
316
|
-
|
317
|
-
// Sort the object's values by a criterion produced by an iterator.
|
318
|
-
_.sortBy = function(obj, iterator, context) {
|
319
|
-
iterator = lookupIterator(iterator);
|
337
|
+
// Sort the object's values by a criterion produced by an iteratee.
|
338
|
+
_.sortBy = function(obj, iteratee, context) {
|
339
|
+
iteratee = _.iteratee(iteratee, context);
|
320
340
|
return _.pluck(_.map(obj, function(value, index, list) {
|
321
341
|
return {
|
322
342
|
value: value,
|
323
343
|
index: index,
|
324
|
-
criteria:
|
344
|
+
criteria: iteratee(value, index, list)
|
325
345
|
};
|
326
346
|
}).sort(function(left, right) {
|
327
347
|
var a = left.criteria;
|
@@ -336,12 +356,12 @@
|
|
336
356
|
|
337
357
|
// An internal function used for aggregate "group by" operations.
|
338
358
|
var group = function(behavior) {
|
339
|
-
return function(obj,
|
359
|
+
return function(obj, iteratee, context) {
|
340
360
|
var result = {};
|
341
|
-
|
342
|
-
each(obj, function(value, index) {
|
343
|
-
var key =
|
344
|
-
behavior(result,
|
361
|
+
iteratee = _.iteratee(iteratee, context);
|
362
|
+
_.each(obj, function(value, index) {
|
363
|
+
var key = iteratee(value, index, obj);
|
364
|
+
behavior(result, value, key);
|
345
365
|
});
|
346
366
|
return result;
|
347
367
|
};
|
@@ -349,32 +369,32 @@
|
|
349
369
|
|
350
370
|
// Groups the object's values by a criterion. Pass either a string attribute
|
351
371
|
// to group by, or a function that returns the criterion.
|
352
|
-
_.groupBy = group(function(result,
|
353
|
-
_.has(result, key)
|
372
|
+
_.groupBy = group(function(result, value, key) {
|
373
|
+
if (_.has(result, key)) result[key].push(value); else result[key] = [value];
|
354
374
|
});
|
355
375
|
|
356
376
|
// Indexes the object's values by a criterion, similar to `groupBy`, but for
|
357
377
|
// when you know that your index values will be unique.
|
358
|
-
_.indexBy = group(function(result,
|
378
|
+
_.indexBy = group(function(result, value, key) {
|
359
379
|
result[key] = value;
|
360
380
|
});
|
361
381
|
|
362
382
|
// Counts instances of an object that group by a certain criterion. Pass
|
363
383
|
// either a string attribute to count by, or a function that returns the
|
364
384
|
// criterion.
|
365
|
-
_.countBy = group(function(result, key) {
|
366
|
-
_.has(result, key)
|
385
|
+
_.countBy = group(function(result, value, key) {
|
386
|
+
if (_.has(result, key)) result[key]++; else result[key] = 1;
|
367
387
|
});
|
368
388
|
|
369
389
|
// Use a comparator function to figure out the smallest index at which
|
370
390
|
// an object should be inserted so as to maintain order. Uses binary search.
|
371
|
-
_.sortedIndex = function(array, obj,
|
372
|
-
|
373
|
-
var value =
|
391
|
+
_.sortedIndex = function(array, obj, iteratee, context) {
|
392
|
+
iteratee = _.iteratee(iteratee, context, 1);
|
393
|
+
var value = iteratee(obj);
|
374
394
|
var low = 0, high = array.length;
|
375
395
|
while (low < high) {
|
376
|
-
var mid =
|
377
|
-
|
396
|
+
var mid = low + high >>> 1;
|
397
|
+
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
|
378
398
|
}
|
379
399
|
return low;
|
380
400
|
};
|
@@ -390,7 +410,18 @@
|
|
390
410
|
// Return the number of elements in an object.
|
391
411
|
_.size = function(obj) {
|
392
412
|
if (obj == null) return 0;
|
393
|
-
return
|
413
|
+
return obj.length === +obj.length ? obj.length : _.keys(obj).length;
|
414
|
+
};
|
415
|
+
|
416
|
+
// Split a collection into two arrays: one whose elements all satisfy the given
|
417
|
+
// predicate, and one whose elements all do not satisfy the predicate.
|
418
|
+
_.partition = function(obj, predicate, context) {
|
419
|
+
predicate = _.iteratee(predicate, context);
|
420
|
+
var pass = [], fail = [];
|
421
|
+
_.each(obj, function(value, key, obj) {
|
422
|
+
(predicate(value, key, obj) ? pass : fail).push(value);
|
423
|
+
});
|
424
|
+
return [pass, fail];
|
394
425
|
};
|
395
426
|
|
396
427
|
// Array Functions
|
@@ -401,7 +432,7 @@
|
|
401
432
|
// allows it to work with `_.map`.
|
402
433
|
_.first = _.head = _.take = function(array, n, guard) {
|
403
434
|
if (array == null) return void 0;
|
404
|
-
if (
|
435
|
+
if (n == null || guard) return array[0];
|
405
436
|
if (n < 0) return [];
|
406
437
|
return slice.call(array, 0, n);
|
407
438
|
};
|
@@ -411,14 +442,14 @@
|
|
411
442
|
// the array, excluding the last N. The **guard** check allows it to work with
|
412
443
|
// `_.map`.
|
413
444
|
_.initial = function(array, n, guard) {
|
414
|
-
return slice.call(array, 0, array.length - (
|
445
|
+
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
|
415
446
|
};
|
416
447
|
|
417
448
|
// Get the last element of an array. Passing **n** will return the last N
|
418
449
|
// values in the array. The **guard** check allows it to work with `_.map`.
|
419
450
|
_.last = function(array, n, guard) {
|
420
451
|
if (array == null) return void 0;
|
421
|
-
if (
|
452
|
+
if (n == null || guard) return array[array.length - 1];
|
422
453
|
return slice.call(array, Math.max(array.length - n, 0));
|
423
454
|
};
|
424
455
|
|
@@ -427,7 +458,7 @@
|
|
427
458
|
// the rest N values in the array. The **guard**
|
428
459
|
// check allows it to work with `_.map`.
|
429
460
|
_.rest = _.tail = _.drop = function(array, n, guard) {
|
430
|
-
return slice.call(array,
|
461
|
+
return slice.call(array, n == null || guard ? 1 : n);
|
431
462
|
};
|
432
463
|
|
433
464
|
// Trim out all falsy values from an array.
|
@@ -436,23 +467,26 @@
|
|
436
467
|
};
|
437
468
|
|
438
469
|
// Internal implementation of a recursive `flatten` function.
|
439
|
-
var flatten = function(input, shallow, output) {
|
470
|
+
var flatten = function(input, shallow, strict, output) {
|
440
471
|
if (shallow && _.every(input, _.isArray)) {
|
441
472
|
return concat.apply(output, input);
|
442
473
|
}
|
443
|
-
|
444
|
-
|
445
|
-
|
474
|
+
for (var i = 0, length = input.length; i < length; i++) {
|
475
|
+
var value = input[i];
|
476
|
+
if (!_.isArray(value) && !_.isArguments(value)) {
|
477
|
+
if (!strict) output.push(value);
|
478
|
+
} else if (shallow) {
|
479
|
+
push.apply(output, value);
|
446
480
|
} else {
|
447
|
-
|
481
|
+
flatten(value, shallow, strict, output);
|
448
482
|
}
|
449
|
-
}
|
483
|
+
}
|
450
484
|
return output;
|
451
485
|
};
|
452
486
|
|
453
487
|
// Flatten out an array, either recursively (by default), or just one level.
|
454
488
|
_.flatten = function(array, shallow) {
|
455
|
-
return flatten(array, shallow, []);
|
489
|
+
return flatten(array, shallow, false, []);
|
456
490
|
};
|
457
491
|
|
458
492
|
// Return a version of the array that does not contain the specified value(s).
|
@@ -460,68 +494,77 @@
|
|
460
494
|
return _.difference(array, slice.call(arguments, 1));
|
461
495
|
};
|
462
496
|
|
463
|
-
// Split an array into two arrays: one whose elements all satisfy the given
|
464
|
-
// predicate, and one whose elements all do not satisfy the predicate.
|
465
|
-
_.partition = function(array, predicate) {
|
466
|
-
var pass = [], fail = [];
|
467
|
-
each(array, function(elem) {
|
468
|
-
(predicate(elem) ? pass : fail).push(elem);
|
469
|
-
});
|
470
|
-
return [pass, fail];
|
471
|
-
};
|
472
|
-
|
473
497
|
// Produce a duplicate-free version of the array. If the array has already
|
474
498
|
// been sorted, you have the option of using a faster algorithm.
|
475
499
|
// Aliased as `unique`.
|
476
|
-
_.uniq = _.unique = function(array, isSorted,
|
477
|
-
if (
|
478
|
-
|
479
|
-
|
500
|
+
_.uniq = _.unique = function(array, isSorted, iteratee, context) {
|
501
|
+
if (array == null) return [];
|
502
|
+
if (!_.isBoolean(isSorted)) {
|
503
|
+
context = iteratee;
|
504
|
+
iteratee = isSorted;
|
480
505
|
isSorted = false;
|
481
506
|
}
|
482
|
-
|
483
|
-
var
|
507
|
+
if (iteratee != null) iteratee = _.iteratee(iteratee, context);
|
508
|
+
var result = [];
|
484
509
|
var seen = [];
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
510
|
+
for (var i = 0, length = array.length; i < length; i++) {
|
511
|
+
var value = array[i];
|
512
|
+
if (isSorted) {
|
513
|
+
if (!i || seen !== value) result.push(value);
|
514
|
+
seen = value;
|
515
|
+
} else if (iteratee) {
|
516
|
+
var computed = iteratee(value, i, array);
|
517
|
+
if (_.indexOf(seen, computed) < 0) {
|
518
|
+
seen.push(computed);
|
519
|
+
result.push(value);
|
520
|
+
}
|
521
|
+
} else if (_.indexOf(result, value) < 0) {
|
522
|
+
result.push(value);
|
489
523
|
}
|
490
|
-
}
|
491
|
-
return
|
524
|
+
}
|
525
|
+
return result;
|
492
526
|
};
|
493
527
|
|
494
528
|
// Produce an array that contains the union: each distinct element from all of
|
495
529
|
// the passed-in arrays.
|
496
530
|
_.union = function() {
|
497
|
-
return _.uniq(
|
531
|
+
return _.uniq(flatten(arguments, true, true, []));
|
498
532
|
};
|
499
533
|
|
500
534
|
// Produce an array that contains every item shared between all the
|
501
535
|
// passed-in arrays.
|
502
536
|
_.intersection = function(array) {
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
537
|
+
if (array == null) return [];
|
538
|
+
var result = [];
|
539
|
+
var argsLength = arguments.length;
|
540
|
+
for (var i = 0, length = array.length; i < length; i++) {
|
541
|
+
var item = array[i];
|
542
|
+
if (_.contains(result, item)) continue;
|
543
|
+
for (var j = 1; j < argsLength; j++) {
|
544
|
+
if (!_.contains(arguments[j], item)) break;
|
545
|
+
}
|
546
|
+
if (j === argsLength) result.push(item);
|
547
|
+
}
|
548
|
+
return result;
|
509
549
|
};
|
510
550
|
|
511
551
|
// Take the difference between one array and a number of other arrays.
|
512
552
|
// Only the elements present in just the first array will remain.
|
513
553
|
_.difference = function(array) {
|
514
|
-
var rest =
|
515
|
-
return _.filter(array, function(value){
|
554
|
+
var rest = flatten(slice.call(arguments, 1), true, true, []);
|
555
|
+
return _.filter(array, function(value){
|
556
|
+
return !_.contains(rest, value);
|
557
|
+
});
|
516
558
|
};
|
517
559
|
|
518
560
|
// Zip together multiple lists into a single array -- elements that share
|
519
561
|
// an index go together.
|
520
|
-
_.zip = function() {
|
521
|
-
|
522
|
-
var
|
562
|
+
_.zip = function(array) {
|
563
|
+
if (array == null) return [];
|
564
|
+
var length = _.max(arguments, 'length').length;
|
565
|
+
var results = Array(length);
|
523
566
|
for (var i = 0; i < length; i++) {
|
524
|
-
results[i] = _.pluck(arguments,
|
567
|
+
results[i] = _.pluck(arguments, i);
|
525
568
|
}
|
526
569
|
return results;
|
527
570
|
};
|
@@ -542,10 +585,8 @@
|
|
542
585
|
return result;
|
543
586
|
};
|
544
587
|
|
545
|
-
//
|
546
|
-
//
|
547
|
-
// item in an array, or -1 if the item is not included in the array.
|
548
|
-
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
|
588
|
+
// Return the position of the first occurrence of an item in an array,
|
589
|
+
// or -1 if the item is not included in the array.
|
549
590
|
// If the array is large and already in sort order, pass `true`
|
550
591
|
// for **isSorted** to use binary search.
|
551
592
|
_.indexOf = function(array, item, isSorted) {
|
@@ -553,26 +594,23 @@
|
|
553
594
|
var i = 0, length = array.length;
|
554
595
|
if (isSorted) {
|
555
596
|
if (typeof isSorted == 'number') {
|
556
|
-
i =
|
597
|
+
i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
|
557
598
|
} else {
|
558
599
|
i = _.sortedIndex(array, item);
|
559
600
|
return array[i] === item ? i : -1;
|
560
601
|
}
|
561
602
|
}
|
562
|
-
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
|
563
603
|
for (; i < length; i++) if (array[i] === item) return i;
|
564
604
|
return -1;
|
565
605
|
};
|
566
606
|
|
567
|
-
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
568
607
|
_.lastIndexOf = function(array, item, from) {
|
569
608
|
if (array == null) return -1;
|
570
|
-
var
|
571
|
-
if (
|
572
|
-
|
609
|
+
var idx = array.length;
|
610
|
+
if (typeof from == 'number') {
|
611
|
+
idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
|
573
612
|
}
|
574
|
-
|
575
|
-
while (i--) if (array[i] === item) return i;
|
613
|
+
while (--idx >= 0) if (array[idx] === item) return idx;
|
576
614
|
return -1;
|
577
615
|
};
|
578
616
|
|
@@ -584,15 +622,13 @@
|
|
584
622
|
stop = start || 0;
|
585
623
|
start = 0;
|
586
624
|
}
|
587
|
-
step =
|
625
|
+
step = step || 1;
|
588
626
|
|
589
627
|
var length = Math.max(Math.ceil((stop - start) / step), 0);
|
590
|
-
var
|
591
|
-
var range = new Array(length);
|
628
|
+
var range = Array(length);
|
592
629
|
|
593
|
-
|
594
|
-
range[idx
|
595
|
-
start += step;
|
630
|
+
for (var idx = 0; idx < length; idx++, start += step) {
|
631
|
+
range[idx] = start;
|
596
632
|
}
|
597
633
|
|
598
634
|
return range;
|
@@ -602,7 +638,7 @@
|
|
602
638
|
// ------------------
|
603
639
|
|
604
640
|
// Reusable constructor function for prototype setting.
|
605
|
-
var
|
641
|
+
var Ctor = function(){};
|
606
642
|
|
607
643
|
// Create a function bound to a given object (assigning `this`, and arguments,
|
608
644
|
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
|
@@ -610,17 +646,18 @@
|
|
610
646
|
_.bind = function(func, context) {
|
611
647
|
var args, bound;
|
612
648
|
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
613
|
-
if (!_.isFunction(func)) throw new TypeError;
|
649
|
+
if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
|
614
650
|
args = slice.call(arguments, 2);
|
615
|
-
|
651
|
+
bound = function() {
|
616
652
|
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
|
617
|
-
|
618
|
-
var self = new
|
619
|
-
|
653
|
+
Ctor.prototype = func.prototype;
|
654
|
+
var self = new Ctor;
|
655
|
+
Ctor.prototype = null;
|
620
656
|
var result = func.apply(self, args.concat(slice.call(arguments)));
|
621
|
-
if (
|
657
|
+
if (_.isObject(result)) return result;
|
622
658
|
return self;
|
623
659
|
};
|
660
|
+
return bound;
|
624
661
|
};
|
625
662
|
|
626
663
|
// Partially apply a function by creating a version that has had some of its
|
@@ -643,27 +680,34 @@
|
|
643
680
|
// are the method names to be bound. Useful for ensuring that all callbacks
|
644
681
|
// defined on an object belong to it.
|
645
682
|
_.bindAll = function(obj) {
|
646
|
-
var
|
647
|
-
if (
|
648
|
-
|
683
|
+
var i, length = arguments.length, key;
|
684
|
+
if (length <= 1) throw new Error('bindAll must be passed function names');
|
685
|
+
for (i = 1; i < length; i++) {
|
686
|
+
key = arguments[i];
|
687
|
+
obj[key] = _.bind(obj[key], obj);
|
688
|
+
}
|
649
689
|
return obj;
|
650
690
|
};
|
651
691
|
|
652
692
|
// Memoize an expensive function by storing its results.
|
653
693
|
_.memoize = function(func, hasher) {
|
654
|
-
var
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
return
|
694
|
+
var memoize = function(key) {
|
695
|
+
var cache = memoize.cache;
|
696
|
+
var address = hasher ? hasher.apply(this, arguments) : key;
|
697
|
+
if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
|
698
|
+
return cache[address];
|
659
699
|
};
|
700
|
+
memoize.cache = {};
|
701
|
+
return memoize;
|
660
702
|
};
|
661
703
|
|
662
704
|
// Delays a function for the given number of milliseconds, and then calls
|
663
705
|
// it with the arguments supplied.
|
664
706
|
_.delay = function(func, wait) {
|
665
707
|
var args = slice.call(arguments, 2);
|
666
|
-
return setTimeout(function(){
|
708
|
+
return setTimeout(function(){
|
709
|
+
return func.apply(null, args);
|
710
|
+
}, wait);
|
667
711
|
};
|
668
712
|
|
669
713
|
// Defers a function, scheduling it to run after the current call stack has
|
@@ -681,12 +725,12 @@
|
|
681
725
|
var context, args, result;
|
682
726
|
var timeout = null;
|
683
727
|
var previous = 0;
|
684
|
-
|
728
|
+
if (!options) options = {};
|
685
729
|
var later = function() {
|
686
730
|
previous = options.leading === false ? 0 : _.now();
|
687
731
|
timeout = null;
|
688
732
|
result = func.apply(context, args);
|
689
|
-
context = args = null;
|
733
|
+
if (!timeout) context = args = null;
|
690
734
|
};
|
691
735
|
return function() {
|
692
736
|
var now = _.now();
|
@@ -694,12 +738,12 @@
|
|
694
738
|
var remaining = wait - (now - previous);
|
695
739
|
context = this;
|
696
740
|
args = arguments;
|
697
|
-
if (remaining <= 0) {
|
741
|
+
if (remaining <= 0 || remaining > wait) {
|
698
742
|
clearTimeout(timeout);
|
699
743
|
timeout = null;
|
700
744
|
previous = now;
|
701
745
|
result = func.apply(context, args);
|
702
|
-
context = args = null;
|
746
|
+
if (!timeout) context = args = null;
|
703
747
|
} else if (!timeout && options.trailing !== false) {
|
704
748
|
timeout = setTimeout(later, remaining);
|
705
749
|
}
|
@@ -716,13 +760,14 @@
|
|
716
760
|
|
717
761
|
var later = function() {
|
718
762
|
var last = _.now() - timestamp;
|
719
|
-
|
763
|
+
|
764
|
+
if (last < wait && last > 0) {
|
720
765
|
timeout = setTimeout(later, wait - last);
|
721
766
|
} else {
|
722
767
|
timeout = null;
|
723
768
|
if (!immediate) {
|
724
769
|
result = func.apply(context, args);
|
725
|
-
context = args = null;
|
770
|
+
if (!timeout) context = args = null;
|
726
771
|
}
|
727
772
|
}
|
728
773
|
};
|
@@ -732,9 +777,7 @@
|
|
732
777
|
args = arguments;
|
733
778
|
timestamp = _.now();
|
734
779
|
var callNow = immediate && !timeout;
|
735
|
-
if (!timeout)
|
736
|
-
timeout = setTimeout(later, wait);
|
737
|
-
}
|
780
|
+
if (!timeout) timeout = setTimeout(later, wait);
|
738
781
|
if (callNow) {
|
739
782
|
result = func.apply(context, args);
|
740
783
|
context = args = null;
|
@@ -744,19 +787,6 @@
|
|
744
787
|
};
|
745
788
|
};
|
746
789
|
|
747
|
-
// Returns a function that will be executed at most one time, no matter how
|
748
|
-
// often you call it. Useful for lazy initialization.
|
749
|
-
_.once = function(func) {
|
750
|
-
var ran = false, memo;
|
751
|
-
return function() {
|
752
|
-
if (ran) return memo;
|
753
|
-
ran = true;
|
754
|
-
memo = func.apply(this, arguments);
|
755
|
-
func = null;
|
756
|
-
return memo;
|
757
|
-
};
|
758
|
-
};
|
759
|
-
|
760
790
|
// Returns the first function passed as an argument to the second,
|
761
791
|
// allowing you to adjust arguments, run code before and after, and
|
762
792
|
// conditionally execute the original function.
|
@@ -764,16 +794,23 @@
|
|
764
794
|
return _.partial(wrapper, func);
|
765
795
|
};
|
766
796
|
|
797
|
+
// Returns a negated version of the passed-in predicate.
|
798
|
+
_.negate = function(predicate) {
|
799
|
+
return function() {
|
800
|
+
return !predicate.apply(this, arguments);
|
801
|
+
};
|
802
|
+
};
|
803
|
+
|
767
804
|
// Returns a function that is the composition of a list of functions, each
|
768
805
|
// consuming the return value of the function that follows.
|
769
806
|
_.compose = function() {
|
770
|
-
var
|
807
|
+
var args = arguments;
|
808
|
+
var start = args.length - 1;
|
771
809
|
return function() {
|
772
|
-
var
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
return args[0];
|
810
|
+
var i = start;
|
811
|
+
var result = args[start].apply(this, arguments);
|
812
|
+
while (i--) result = args[i].call(this, result);
|
813
|
+
return result;
|
777
814
|
};
|
778
815
|
};
|
779
816
|
|
@@ -786,6 +823,23 @@
|
|
786
823
|
};
|
787
824
|
};
|
788
825
|
|
826
|
+
// Returns a function that will only be executed before being called N times.
|
827
|
+
_.before = function(times, func) {
|
828
|
+
var memo;
|
829
|
+
return function() {
|
830
|
+
if (--times > 0) {
|
831
|
+
memo = func.apply(this, arguments);
|
832
|
+
} else {
|
833
|
+
func = null;
|
834
|
+
}
|
835
|
+
return memo;
|
836
|
+
};
|
837
|
+
};
|
838
|
+
|
839
|
+
// Returns a function that will be executed at most one time, no matter how
|
840
|
+
// often you call it. Useful for lazy initialization.
|
841
|
+
_.once = _.partial(_.before, 2);
|
842
|
+
|
789
843
|
// Object Functions
|
790
844
|
// ----------------
|
791
845
|
|
@@ -803,7 +857,7 @@
|
|
803
857
|
_.values = function(obj) {
|
804
858
|
var keys = _.keys(obj);
|
805
859
|
var length = keys.length;
|
806
|
-
var values =
|
860
|
+
var values = Array(length);
|
807
861
|
for (var i = 0; i < length; i++) {
|
808
862
|
values[i] = obj[keys[i]];
|
809
863
|
}
|
@@ -814,7 +868,7 @@
|
|
814
868
|
_.pairs = function(obj) {
|
815
869
|
var keys = _.keys(obj);
|
816
870
|
var length = keys.length;
|
817
|
-
var pairs =
|
871
|
+
var pairs = Array(length);
|
818
872
|
for (var i = 0; i < length; i++) {
|
819
873
|
pairs[i] = [keys[i], obj[keys[i]]];
|
820
874
|
}
|
@@ -843,45 +897,62 @@
|
|
843
897
|
|
844
898
|
// Extend a given object with all the properties in passed-in object(s).
|
845
899
|
_.extend = function(obj) {
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
900
|
+
if (!_.isObject(obj)) return obj;
|
901
|
+
var source, prop;
|
902
|
+
for (var i = 1, length = arguments.length; i < length; i++) {
|
903
|
+
source = arguments[i];
|
904
|
+
for (prop in source) {
|
905
|
+
if (hasOwnProperty.call(source, prop)) {
|
906
|
+
obj[prop] = source[prop];
|
850
907
|
}
|
851
908
|
}
|
852
|
-
}
|
909
|
+
}
|
853
910
|
return obj;
|
854
911
|
};
|
855
912
|
|
856
913
|
// Return a copy of the object only containing the whitelisted properties.
|
857
|
-
_.pick = function(obj) {
|
858
|
-
var
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
914
|
+
_.pick = function(obj, iteratee, context) {
|
915
|
+
var result = {}, key;
|
916
|
+
if (obj == null) return result;
|
917
|
+
if (_.isFunction(iteratee)) {
|
918
|
+
iteratee = createCallback(iteratee, context);
|
919
|
+
for (key in obj) {
|
920
|
+
var value = obj[key];
|
921
|
+
if (iteratee(value, key, obj)) result[key] = value;
|
922
|
+
}
|
923
|
+
} else {
|
924
|
+
var keys = concat.apply([], slice.call(arguments, 1));
|
925
|
+
obj = new Object(obj);
|
926
|
+
for (var i = 0, length = keys.length; i < length; i++) {
|
927
|
+
key = keys[i];
|
928
|
+
if (key in obj) result[key] = obj[key];
|
929
|
+
}
|
930
|
+
}
|
931
|
+
return result;
|
864
932
|
};
|
865
933
|
|
866
934
|
// Return a copy of the object without the blacklisted properties.
|
867
|
-
_.omit = function(obj) {
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
935
|
+
_.omit = function(obj, iteratee, context) {
|
936
|
+
if (_.isFunction(iteratee)) {
|
937
|
+
iteratee = _.negate(iteratee);
|
938
|
+
} else {
|
939
|
+
var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
|
940
|
+
iteratee = function(value, key) {
|
941
|
+
return !_.contains(keys, key);
|
942
|
+
};
|
872
943
|
}
|
873
|
-
return
|
944
|
+
return _.pick(obj, iteratee, context);
|
874
945
|
};
|
875
946
|
|
876
947
|
// Fill in a given object with default properties.
|
877
948
|
_.defaults = function(obj) {
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
949
|
+
if (!_.isObject(obj)) return obj;
|
950
|
+
for (var i = 1, length = arguments.length; i < length; i++) {
|
951
|
+
var source = arguments[i];
|
952
|
+
for (var prop in source) {
|
953
|
+
if (obj[prop] === void 0) obj[prop] = source[prop];
|
883
954
|
}
|
884
|
-
}
|
955
|
+
}
|
885
956
|
return obj;
|
886
957
|
};
|
887
958
|
|
@@ -903,7 +974,7 @@
|
|
903
974
|
var eq = function(a, b, aStack, bStack) {
|
904
975
|
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
905
976
|
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
906
|
-
if (a === b) return a !== 0 || 1 / a
|
977
|
+
if (a === b) return a !== 0 || 1 / a === 1 / b;
|
907
978
|
// A strict comparison is necessary because `null == undefined`.
|
908
979
|
if (a == null || b == null) return a === b;
|
909
980
|
// Unwrap any wrapped objects.
|
@@ -911,29 +982,27 @@
|
|
911
982
|
if (b instanceof _) b = b._wrapped;
|
912
983
|
// Compare `[[Class]]` names.
|
913
984
|
var className = toString.call(a);
|
914
|
-
if (className
|
985
|
+
if (className !== toString.call(b)) return false;
|
915
986
|
switch (className) {
|
916
|
-
// Strings, numbers, dates, and booleans are compared by value.
|
987
|
+
// Strings, numbers, regular expressions, dates, and booleans are compared by value.
|
988
|
+
case '[object RegExp]':
|
989
|
+
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
|
917
990
|
case '[object String]':
|
918
991
|
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
919
992
|
// equivalent to `new String("5")`.
|
920
|
-
return a
|
993
|
+
return '' + a === '' + b;
|
921
994
|
case '[object Number]':
|
922
|
-
// `NaN`s are equivalent, but non-reflexive.
|
923
|
-
//
|
924
|
-
|
995
|
+
// `NaN`s are equivalent, but non-reflexive.
|
996
|
+
// Object(NaN) is equivalent to NaN
|
997
|
+
if (+a !== +a) return +b !== +b;
|
998
|
+
// An `egal` comparison is performed for other numeric values.
|
999
|
+
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
|
925
1000
|
case '[object Date]':
|
926
1001
|
case '[object Boolean]':
|
927
1002
|
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
928
1003
|
// millisecond representations. Note that invalid dates with millisecond representations
|
929
1004
|
// of `NaN` are not equivalent.
|
930
|
-
return +a
|
931
|
-
// RegExps are compared by their source patterns and flags.
|
932
|
-
case '[object RegExp]':
|
933
|
-
return a.source == b.source &&
|
934
|
-
a.global == b.global &&
|
935
|
-
a.multiline == b.multiline &&
|
936
|
-
a.ignoreCase == b.ignoreCase;
|
1005
|
+
return +a === +b;
|
937
1006
|
}
|
938
1007
|
if (typeof a != 'object' || typeof b != 'object') return false;
|
939
1008
|
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
@@ -942,25 +1011,29 @@
|
|
942
1011
|
while (length--) {
|
943
1012
|
// Linear search. Performance is inversely proportional to the number of
|
944
1013
|
// unique nested structures.
|
945
|
-
if (aStack[length]
|
1014
|
+
if (aStack[length] === a) return bStack[length] === b;
|
946
1015
|
}
|
947
1016
|
// Objects with different constructors are not equivalent, but `Object`s
|
948
1017
|
// from different frames are.
|
949
1018
|
var aCtor = a.constructor, bCtor = b.constructor;
|
950
|
-
if (
|
951
|
-
|
952
|
-
|
1019
|
+
if (
|
1020
|
+
aCtor !== bCtor &&
|
1021
|
+
// Handle Object.create(x) cases
|
1022
|
+
'constructor' in a && 'constructor' in b &&
|
1023
|
+
!(_.isFunction(aCtor) && aCtor instanceof aCtor &&
|
1024
|
+
_.isFunction(bCtor) && bCtor instanceof bCtor)
|
1025
|
+
) {
|
953
1026
|
return false;
|
954
1027
|
}
|
955
1028
|
// Add the first object to the stack of traversed objects.
|
956
1029
|
aStack.push(a);
|
957
1030
|
bStack.push(b);
|
958
|
-
var size
|
1031
|
+
var size, result;
|
959
1032
|
// Recursively compare objects and arrays.
|
960
|
-
if (className
|
1033
|
+
if (className === '[object Array]') {
|
961
1034
|
// Compare array lengths to determine if a deep comparison is necessary.
|
962
1035
|
size = a.length;
|
963
|
-
result = size
|
1036
|
+
result = size === b.length;
|
964
1037
|
if (result) {
|
965
1038
|
// Deep compare the contents, ignoring non-numeric properties.
|
966
1039
|
while (size--) {
|
@@ -969,20 +1042,16 @@
|
|
969
1042
|
}
|
970
1043
|
} else {
|
971
1044
|
// Deep compare objects.
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
// Deep compare each member.
|
977
|
-
if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
|
978
|
-
}
|
979
|
-
}
|
980
|
-
// Ensure that both objects contain the same number of properties.
|
1045
|
+
var keys = _.keys(a), key;
|
1046
|
+
size = keys.length;
|
1047
|
+
// Ensure that both objects contain the same number of properties before comparing deep equality.
|
1048
|
+
result = _.keys(b).length === size;
|
981
1049
|
if (result) {
|
982
|
-
|
983
|
-
|
1050
|
+
while (size--) {
|
1051
|
+
// Deep compare each member
|
1052
|
+
key = keys[size];
|
1053
|
+
if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
|
984
1054
|
}
|
985
|
-
result = !size;
|
986
1055
|
}
|
987
1056
|
}
|
988
1057
|
// Remove the first object from the stack of traversed objects.
|
@@ -1000,7 +1069,7 @@
|
|
1000
1069
|
// An "empty" object has no enumerable own-properties.
|
1001
1070
|
_.isEmpty = function(obj) {
|
1002
1071
|
if (obj == null) return true;
|
1003
|
-
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
1072
|
+
if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
|
1004
1073
|
for (var key in obj) if (_.has(obj, key)) return false;
|
1005
1074
|
return true;
|
1006
1075
|
};
|
@@ -1013,18 +1082,19 @@
|
|
1013
1082
|
// Is a given value an array?
|
1014
1083
|
// Delegates to ECMA5's native Array.isArray
|
1015
1084
|
_.isArray = nativeIsArray || function(obj) {
|
1016
|
-
return toString.call(obj)
|
1085
|
+
return toString.call(obj) === '[object Array]';
|
1017
1086
|
};
|
1018
1087
|
|
1019
1088
|
// Is a given variable an object?
|
1020
1089
|
_.isObject = function(obj) {
|
1021
|
-
|
1090
|
+
var type = typeof obj;
|
1091
|
+
return type === 'function' || type === 'object' && !!obj;
|
1022
1092
|
};
|
1023
1093
|
|
1024
1094
|
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
|
1025
|
-
each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
1095
|
+
_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
1026
1096
|
_['is' + name] = function(obj) {
|
1027
|
-
return toString.call(obj)
|
1097
|
+
return toString.call(obj) === '[object ' + name + ']';
|
1028
1098
|
};
|
1029
1099
|
});
|
1030
1100
|
|
@@ -1032,14 +1102,14 @@
|
|
1032
1102
|
// there isn't any inspectable "Arguments" type.
|
1033
1103
|
if (!_.isArguments(arguments)) {
|
1034
1104
|
_.isArguments = function(obj) {
|
1035
|
-
return
|
1105
|
+
return _.has(obj, 'callee');
|
1036
1106
|
};
|
1037
1107
|
}
|
1038
1108
|
|
1039
|
-
// Optimize `isFunction` if appropriate.
|
1040
|
-
if (typeof
|
1109
|
+
// Optimize `isFunction` if appropriate. Work around an IE 11 bug.
|
1110
|
+
if (typeof /./ !== 'function') {
|
1041
1111
|
_.isFunction = function(obj) {
|
1042
|
-
return typeof obj
|
1112
|
+
return typeof obj == 'function' || false;
|
1043
1113
|
};
|
1044
1114
|
}
|
1045
1115
|
|
@@ -1050,12 +1120,12 @@
|
|
1050
1120
|
|
1051
1121
|
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
|
1052
1122
|
_.isNaN = function(obj) {
|
1053
|
-
return _.isNumber(obj) && obj
|
1123
|
+
return _.isNumber(obj) && obj !== +obj;
|
1054
1124
|
};
|
1055
1125
|
|
1056
1126
|
// Is a given value a boolean?
|
1057
1127
|
_.isBoolean = function(obj) {
|
1058
|
-
return obj === true || obj === false || toString.call(obj)
|
1128
|
+
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
|
1059
1129
|
};
|
1060
1130
|
|
1061
1131
|
// Is a given value equal to null?
|
@@ -1071,7 +1141,7 @@
|
|
1071
1141
|
// Shortcut function for checking if an object has a given property directly
|
1072
1142
|
// on itself (in other words, not on a prototype).
|
1073
1143
|
_.has = function(obj, key) {
|
1074
|
-
return hasOwnProperty.call(obj, key);
|
1144
|
+
return obj != null && hasOwnProperty.call(obj, key);
|
1075
1145
|
};
|
1076
1146
|
|
1077
1147
|
// Utility Functions
|
@@ -1084,17 +1154,20 @@
|
|
1084
1154
|
return this;
|
1085
1155
|
};
|
1086
1156
|
|
1087
|
-
// Keep the identity function around for default
|
1157
|
+
// Keep the identity function around for default iteratees.
|
1088
1158
|
_.identity = function(value) {
|
1089
1159
|
return value;
|
1090
1160
|
};
|
1091
1161
|
|
1162
|
+
// Predicate-generating functions. Often useful outside of Underscore.
|
1092
1163
|
_.constant = function(value) {
|
1093
|
-
return function
|
1164
|
+
return function() {
|
1094
1165
|
return value;
|
1095
1166
|
};
|
1096
1167
|
};
|
1097
1168
|
|
1169
|
+
_.noop = function(){};
|
1170
|
+
|
1098
1171
|
_.property = function(key) {
|
1099
1172
|
return function(obj) {
|
1100
1173
|
return obj[key];
|
@@ -1103,20 +1176,23 @@
|
|
1103
1176
|
|
1104
1177
|
// Returns a predicate for checking whether an object has a given set of `key:value` pairs.
|
1105
1178
|
_.matches = function(attrs) {
|
1179
|
+
var pairs = _.pairs(attrs), length = pairs.length;
|
1106
1180
|
return function(obj) {
|
1107
|
-
if (obj
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1181
|
+
if (obj == null) return !length;
|
1182
|
+
obj = new Object(obj);
|
1183
|
+
for (var i = 0; i < length; i++) {
|
1184
|
+
var pair = pairs[i], key = pair[0];
|
1185
|
+
if (pair[1] !== obj[key] || !(key in obj)) return false;
|
1111
1186
|
}
|
1112
1187
|
return true;
|
1113
|
-
}
|
1188
|
+
};
|
1114
1189
|
};
|
1115
1190
|
|
1116
1191
|
// Run a function **n** times.
|
1117
|
-
_.times = function(n,
|
1192
|
+
_.times = function(n, iteratee, context) {
|
1118
1193
|
var accum = Array(Math.max(0, n));
|
1119
|
-
|
1194
|
+
iteratee = createCallback(iteratee, context, 1);
|
1195
|
+
for (var i = 0; i < n; i++) accum[i] = iteratee(i);
|
1120
1196
|
return accum;
|
1121
1197
|
};
|
1122
1198
|
|
@@ -1130,54 +1206,44 @@
|
|
1130
1206
|
};
|
1131
1207
|
|
1132
1208
|
// A (possibly faster) way to get the current timestamp as an integer.
|
1133
|
-
_.now = Date.now || function() {
|
1134
|
-
|
1135
|
-
// List of HTML entities for escaping.
|
1136
|
-
var entityMap = {
|
1137
|
-
escape: {
|
1138
|
-
'&': '&',
|
1139
|
-
'<': '<',
|
1140
|
-
'>': '>',
|
1141
|
-
'"': '"',
|
1142
|
-
"'": '''
|
1143
|
-
}
|
1209
|
+
_.now = Date.now || function() {
|
1210
|
+
return new Date().getTime();
|
1144
1211
|
};
|
1145
|
-
entityMap.unescape = _.invert(entityMap.escape);
|
1146
1212
|
|
1147
|
-
|
1148
|
-
var
|
1149
|
-
|
1150
|
-
|
1213
|
+
// List of HTML entities for escaping.
|
1214
|
+
var escapeMap = {
|
1215
|
+
'&': '&',
|
1216
|
+
'<': '<',
|
1217
|
+
'>': '>',
|
1218
|
+
'"': '"',
|
1219
|
+
"'": ''',
|
1220
|
+
'`': '`'
|
1151
1221
|
};
|
1222
|
+
var unescapeMap = _.invert(escapeMap);
|
1152
1223
|
|
1153
1224
|
// Functions for escaping and unescaping strings to/from HTML interpolation.
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
return ('' + string).replace(entityRegexes[method], function(match) {
|
1158
|
-
return entityMap[method][match];
|
1159
|
-
});
|
1225
|
+
var createEscaper = function(map) {
|
1226
|
+
var escaper = function(match) {
|
1227
|
+
return map[match];
|
1160
1228
|
};
|
1161
|
-
|
1229
|
+
// Regexes for identifying a key that needs to be escaped
|
1230
|
+
var source = '(?:' + _.keys(map).join('|') + ')';
|
1231
|
+
var testRegexp = RegExp(source);
|
1232
|
+
var replaceRegexp = RegExp(source, 'g');
|
1233
|
+
return function(string) {
|
1234
|
+
string = string == null ? '' : '' + string;
|
1235
|
+
return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
|
1236
|
+
};
|
1237
|
+
};
|
1238
|
+
_.escape = createEscaper(escapeMap);
|
1239
|
+
_.unescape = createEscaper(unescapeMap);
|
1162
1240
|
|
1163
1241
|
// If the value of the named `property` is a function then invoke it with the
|
1164
1242
|
// `object` as context; otherwise, return it.
|
1165
1243
|
_.result = function(object, property) {
|
1166
1244
|
if (object == null) return void 0;
|
1167
1245
|
var value = object[property];
|
1168
|
-
return _.isFunction(value) ?
|
1169
|
-
};
|
1170
|
-
|
1171
|
-
// Add your own custom functions to the Underscore object.
|
1172
|
-
_.mixin = function(obj) {
|
1173
|
-
each(_.functions(obj), function(name) {
|
1174
|
-
var func = _[name] = obj[name];
|
1175
|
-
_.prototype[name] = function() {
|
1176
|
-
var args = [this._wrapped];
|
1177
|
-
push.apply(args, arguments);
|
1178
|
-
return result.call(this, func.apply(_, args));
|
1179
|
-
};
|
1180
|
-
});
|
1246
|
+
return _.isFunction(value) ? object[property]() : value;
|
1181
1247
|
};
|
1182
1248
|
|
1183
1249
|
// Generate a unique integer id (unique within the entire client session).
|
@@ -1208,22 +1274,26 @@
|
|
1208
1274
|
'\\': '\\',
|
1209
1275
|
'\r': 'r',
|
1210
1276
|
'\n': 'n',
|
1211
|
-
'\t': 't',
|
1212
1277
|
'\u2028': 'u2028',
|
1213
1278
|
'\u2029': 'u2029'
|
1214
1279
|
};
|
1215
1280
|
|
1216
|
-
var escaper = /\\|'|\r|\n|\
|
1281
|
+
var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
|
1282
|
+
|
1283
|
+
var escapeChar = function(match) {
|
1284
|
+
return '\\' + escapes[match];
|
1285
|
+
};
|
1217
1286
|
|
1218
1287
|
// JavaScript micro-templating, similar to John Resig's implementation.
|
1219
1288
|
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
1220
1289
|
// and correctly escapes quotes within interpolated code.
|
1221
|
-
|
1222
|
-
|
1290
|
+
// NB: `oldSettings` only exists for backwards compatibility.
|
1291
|
+
_.template = function(text, settings, oldSettings) {
|
1292
|
+
if (!settings && oldSettings) settings = oldSettings;
|
1223
1293
|
settings = _.defaults({}, settings, _.templateSettings);
|
1224
1294
|
|
1225
1295
|
// Combine delimiters into one regular expression via alternation.
|
1226
|
-
var matcher =
|
1296
|
+
var matcher = RegExp([
|
1227
1297
|
(settings.escape || noMatch).source,
|
1228
1298
|
(settings.interpolate || noMatch).source,
|
1229
1299
|
(settings.evaluate || noMatch).source
|
@@ -1233,19 +1303,18 @@
|
|
1233
1303
|
var index = 0;
|
1234
1304
|
var source = "__p+='";
|
1235
1305
|
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
1236
|
-
source += text.slice(index, offset)
|
1237
|
-
|
1306
|
+
source += text.slice(index, offset).replace(escaper, escapeChar);
|
1307
|
+
index = offset + match.length;
|
1238
1308
|
|
1239
1309
|
if (escape) {
|
1240
1310
|
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
1241
|
-
}
|
1242
|
-
if (interpolate) {
|
1311
|
+
} else if (interpolate) {
|
1243
1312
|
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
1244
|
-
}
|
1245
|
-
if (evaluate) {
|
1313
|
+
} else if (evaluate) {
|
1246
1314
|
source += "';\n" + evaluate + "\n__p+='";
|
1247
1315
|
}
|
1248
|
-
|
1316
|
+
|
1317
|
+
// Adobe VMs need the match returned to produce the correct offest.
|
1249
1318
|
return match;
|
1250
1319
|
});
|
1251
1320
|
source += "';\n";
|
@@ -1255,29 +1324,31 @@
|
|
1255
1324
|
|
1256
1325
|
source = "var __t,__p='',__j=Array.prototype.join," +
|
1257
1326
|
"print=function(){__p+=__j.call(arguments,'');};\n" +
|
1258
|
-
source +
|
1327
|
+
source + 'return __p;\n';
|
1259
1328
|
|
1260
1329
|
try {
|
1261
|
-
render = new Function(settings.variable || 'obj', '_', source);
|
1330
|
+
var render = new Function(settings.variable || 'obj', '_', source);
|
1262
1331
|
} catch (e) {
|
1263
1332
|
e.source = source;
|
1264
1333
|
throw e;
|
1265
1334
|
}
|
1266
1335
|
|
1267
|
-
if (data) return render(data, _);
|
1268
1336
|
var template = function(data) {
|
1269
1337
|
return render.call(this, data, _);
|
1270
1338
|
};
|
1271
1339
|
|
1272
|
-
// Provide the compiled
|
1273
|
-
|
1340
|
+
// Provide the compiled source as a convenience for precompilation.
|
1341
|
+
var argument = settings.variable || 'obj';
|
1342
|
+
template.source = 'function(' + argument + '){\n' + source + '}';
|
1274
1343
|
|
1275
1344
|
return template;
|
1276
1345
|
};
|
1277
1346
|
|
1278
|
-
// Add a "chain" function
|
1347
|
+
// Add a "chain" function. Start chaining a wrapped Underscore object.
|
1279
1348
|
_.chain = function(obj) {
|
1280
|
-
|
1349
|
+
var instance = _(obj);
|
1350
|
+
instance._chain = true;
|
1351
|
+
return instance;
|
1281
1352
|
};
|
1282
1353
|
|
1283
1354
|
// OOP
|
@@ -1291,42 +1362,44 @@
|
|
1291
1362
|
return this._chain ? _(obj).chain() : obj;
|
1292
1363
|
};
|
1293
1364
|
|
1365
|
+
// Add your own custom functions to the Underscore object.
|
1366
|
+
_.mixin = function(obj) {
|
1367
|
+
_.each(_.functions(obj), function(name) {
|
1368
|
+
var func = _[name] = obj[name];
|
1369
|
+
_.prototype[name] = function() {
|
1370
|
+
var args = [this._wrapped];
|
1371
|
+
push.apply(args, arguments);
|
1372
|
+
return result.call(this, func.apply(_, args));
|
1373
|
+
};
|
1374
|
+
});
|
1375
|
+
};
|
1376
|
+
|
1294
1377
|
// Add all of the Underscore functions to the wrapper object.
|
1295
1378
|
_.mixin(_);
|
1296
1379
|
|
1297
1380
|
// Add all mutator Array functions to the wrapper.
|
1298
|
-
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
1381
|
+
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
1299
1382
|
var method = ArrayProto[name];
|
1300
1383
|
_.prototype[name] = function() {
|
1301
1384
|
var obj = this._wrapped;
|
1302
1385
|
method.apply(obj, arguments);
|
1303
|
-
if ((name
|
1386
|
+
if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
|
1304
1387
|
return result.call(this, obj);
|
1305
1388
|
};
|
1306
1389
|
});
|
1307
1390
|
|
1308
1391
|
// Add all accessor Array functions to the wrapper.
|
1309
|
-
each(['concat', 'join', 'slice'], function(name) {
|
1392
|
+
_.each(['concat', 'join', 'slice'], function(name) {
|
1310
1393
|
var method = ArrayProto[name];
|
1311
1394
|
_.prototype[name] = function() {
|
1312
1395
|
return result.call(this, method.apply(this._wrapped, arguments));
|
1313
1396
|
};
|
1314
1397
|
});
|
1315
1398
|
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
this._chain = true;
|
1321
|
-
return this;
|
1322
|
-
},
|
1323
|
-
|
1324
|
-
// Extracts the result from a wrapped and chained object.
|
1325
|
-
value: function() {
|
1326
|
-
return this._wrapped;
|
1327
|
-
}
|
1328
|
-
|
1329
|
-
});
|
1399
|
+
// Extracts the result from a wrapped and chained object.
|
1400
|
+
_.prototype.value = function() {
|
1401
|
+
return this._wrapped;
|
1402
|
+
};
|
1330
1403
|
|
1331
1404
|
// AMD registration happens at the end for compatibility with AMD loaders
|
1332
1405
|
// that may not enforce next-turn semantics on modules. Even though general
|
@@ -1340,4 +1413,4 @@
|
|
1340
1413
|
return _;
|
1341
1414
|
});
|
1342
1415
|
}
|
1343
|
-
}
|
1416
|
+
}.call(this));
|