Add baseGt, baseLt, baseToNumber, baseToString, and createRelationalOperation.

This commit is contained in:
John-David Dalton
2016-04-15 01:05:56 -07:00
parent 1a1e0e1a6b
commit 714cf7b18c

411
lodash.js
View File

@@ -710,35 +710,6 @@
return false;
}
/**
* The base implementation of methods like `_.max` and `_.min` which accepts a
* `comparator` to determine the extremum value.
*
* @private
* @param {Array} array The array to iterate over.
* @param {Function} iteratee The iteratee invoked per iteration.
* @param {Function} comparator The comparator used to compare values.
* @returns {*} Returns the extremum value.
*/
function baseExtremum(array, iteratee, comparator) {
var index = -1,
length = array.length;
while (++index < length) {
var value = array[index],
current = iteratee(value);
if (current != null && (computed === undefined
? current === current
: comparator(current, computed)
)) {
var computed = current,
result = value;
}
}
return result;
}
/**
* The base implementation of methods like `_.find` and `_.findKey`, without
* support for iteratee shorthands, which iterates over `collection` using
@@ -1017,79 +988,6 @@
return (value && value.Object === Object) ? value : null;
}
/**
* Compares values to sort them in ascending order.
*
* @private
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {number} Returns the sort order indicator for `value`.
*/
function compareAscending(value, other) {
if (value !== other) {
var valIsNull = value === null,
valIsUndef = value === undefined,
valIsReflexive = value === value;
var othIsNull = other === null,
othIsUndef = other === undefined,
othIsReflexive = other === other;
if ((value > other && !othIsNull) || !valIsReflexive ||
(valIsNull && !othIsUndef && othIsReflexive) ||
(valIsUndef && othIsReflexive)) {
return 1;
}
if ((value < other && !valIsNull) || !othIsReflexive ||
(othIsNull && !valIsUndef && valIsReflexive) ||
(othIsUndef && valIsReflexive)) {
return -1;
}
}
return 0;
}
/**
* Used by `_.orderBy` to compare multiple properties of a value to another
* and stable sort them.
*
* If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
* specify an order of "desc" for descending or "asc" for ascending sort order
* of corresponding values.
*
* @private
* @param {Object} object The object to compare.
* @param {Object} other The other object to compare.
* @param {boolean[]|string[]} orders The order to sort by for each property.
* @returns {number} Returns the sort order indicator for `object`.
*/
function compareMultiple(object, other, orders) {
var index = -1,
objCriteria = object.criteria,
othCriteria = other.criteria,
length = objCriteria.length,
ordersLength = orders.length;
while (++index < length) {
var result = compareAscending(objCriteria[index], othCriteria[index]);
if (result) {
if (index >= ordersLength) {
return result;
}
var order = orders[index];
return result * (order == 'desc' ? -1 : 1);
}
}
// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
// that causes it, under certain circumstances, to provide the same value for
// `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
// for more details.
//
// This also ensures a stable sort in V8 and other engines.
// See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
return object.index - other.index;
}
/**
* Gets the number of `placeholder` occurrences in `array`.
*
@@ -1110,29 +1008,6 @@
return result;
}
/**
* Creates a function that performs a mathematical operation on two values.
*
* @private
* @param {Function} operator The function to perform the operation.
* @returns {Function} Returns the new mathematical operation function.
*/
function createMathOperation(operator) {
return function(value, other) {
var result;
if (value === undefined && other === undefined) {
return 0;
}
if (value !== undefined) {
result = value;
}
if (other !== undefined) {
result = result === undefined ? other : operator(result, other);
}
return result;
};
}
/**
* Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
*
@@ -2613,6 +2488,35 @@
return result;
}
/**
* The base implementation of methods like `_.max` and `_.min` which accepts a
* `comparator` to determine the extremum value.
*
* @private
* @param {Array} array The array to iterate over.
* @param {Function} iteratee The iteratee invoked per iteration.
* @param {Function} comparator The comparator used to compare values.
* @returns {*} Returns the extremum value.
*/
function baseExtremum(array, iteratee, comparator) {
var index = -1,
length = array.length;
while (++index < length) {
var value = array[index],
current = iteratee(value);
if (current != null && (computed === undefined
? (current === current && !isSymbol(current))
: comparator(current, computed)
)) {
var computed = current,
result = value;
}
}
return result;
}
/**
* The base implementation of `_.fill` without an iteratee call guard.
*
@@ -2795,6 +2699,19 @@
: arrayPush(result, symbolsFunc(object));
}
/**
* The base implementation of `_.gt` which doesn't coerce arguments to numbers.
*
* @private
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if `value` is greater than `other`,
* else `false`.
*/
function baseGt(value, other) {
return value > other;
}
/**
* The base implementation of `_.has` without support for deep paths.
*
@@ -3134,6 +3051,19 @@
};
}
/**
* The base implementation of `_.lt` which doesn't coerce arguments to numbers.
*
* @private
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if `value` is less than `other`,
* else `false`.
*/
function baseLt(value, other) {
return value < other;
}
/**
* The base implementation of `_.map` without support for iteratee shorthands.
*
@@ -3667,7 +3597,8 @@
var mid = (low + high) >>> 1,
computed = array[mid];
if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) {
if (computed !== null && !isSymbol(computed) &&
(retHighest ? (computed <= value) : (computed < value))) {
low = mid + 1;
} else {
high = mid;
@@ -3698,21 +3629,26 @@
high = array ? array.length : 0,
valIsNaN = value !== value,
valIsNull = value === null,
valIsUndef = value === undefined;
valIsSymbol = isSymbol(value),
valIsUndefined = value === undefined;
while (low < high) {
var mid = nativeFloor((low + high) / 2),
computed = iteratee(array[mid]),
isDef = computed !== undefined,
isReflexive = computed === computed;
othIsDefined = computed !== undefined,
othIsNull = computed === null,
othIsReflexive = computed === computed,
othIsSymbol = isSymbol(computed);
if (valIsNaN) {
var setLow = isReflexive || retHighest;
var setLow = retHighest || othIsReflexive;
} else if (valIsUndefined) {
setLow = othIsReflexive && (retHighest || othIsDefined);
} else if (valIsNull) {
setLow = isReflexive && isDef && (retHighest || computed != null);
} else if (valIsUndef) {
setLow = isReflexive && (retHighest || isDef);
} else if (computed == null) {
setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
} else if (valIsSymbol) {
setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
} else if (othIsNull || othIsSymbol) {
setLow = false;
} else {
setLow = retHighest ? (computed <= value) : (computed < value);
@@ -3767,6 +3703,27 @@
return result;
}
function baseToNumber(value) {
if (typeof value == 'number') {
return value;
}
if (isSymbol(value)) {
return NAN;
}
return +value;
}
function baseToString(value) {
// Exit early for strings to avoid a performance hit in some environments.
if (typeof value == 'string') {
return value;
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : '';
}
return (value + '');
}
/**
* The base implementation of `_.uniqBy` without support for iteratee shorthands.
*
@@ -4102,6 +4059,85 @@
return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
}
/**
* Compares values to sort them in ascending order.
*
* @private
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {number} Returns the sort order indicator for `value`.
*/
function compareAscending(value, other) {
if (value !== other) {
var valIsNull = value === null,
valIsUndef = value === undefined,
valIsReflexive = value === value,
valIsSymbol = isSymbol(value);
var othIsNull = other === null,
othIsUndef = other === undefined,
othIsReflexive = other === other,
othIsSymbol = isSymbol(other);
if ((valIsSymbol && !othIsSymbol) ||
(!othIsNull && !othIsSymbol && value > other) ||
(valIsNull && !othIsUndef && othIsReflexive) ||
(valIsUndef && othIsReflexive) ||
!valIsReflexive) {
return 1;
}
if ((othIsSymbol && !valIsSymbol) ||
(!valIsNull && !valIsSymbol && value < other) ||
(othIsNull && !valIsUndef && valIsReflexive) ||
(othIsUndef && valIsReflexive) ||
!othIsReflexive) {
return -1;
}
}
return 0;
}
/**
* Used by `_.orderBy` to compare multiple properties of a value to another
* and stable sort them.
*
* If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
* specify an order of "desc" for descending or "asc" for ascending sort order
* of corresponding values.
*
* @private
* @param {Object} object The object to compare.
* @param {Object} other The other object to compare.
* @param {boolean[]|string[]} orders The order to sort by for each property.
* @returns {number} Returns the sort order indicator for `object`.
*/
function compareMultiple(object, other, orders) {
var index = -1,
objCriteria = object.criteria,
othCriteria = other.criteria,
length = objCriteria.length,
ordersLength = orders.length;
while (++index < length) {
var result = compareAscending(objCriteria[index], othCriteria[index]);
if (result) {
if (index >= ordersLength) {
return result;
}
var order = orders[index];
return result * (order == 'desc' ? -1 : 1);
}
}
// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
// that causes it, under certain circumstances, to provide the same value for
// `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
// for more details.
//
// This also ensures a stable sort in V8 and other engines.
// See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
return object.index - other.index;
}
/**
* Creates an array that is the composition of partially applied arguments,
* placeholders, and provided arguments into a single array of arguments.
@@ -4621,6 +4657,39 @@
};
}
/**
* Creates a function that performs a mathematical operation on two values.
*
* @private
* @param {Function} operator The function to perform the operation.
* @returns {Function} Returns the new mathematical operation function.
*/
function createMathOperation(operator) {
return function(value, other) {
var result;
if (value === undefined && other === undefined) {
return 0;
}
if (value !== undefined) {
result = value;
}
if (other !== undefined) {
if (result === undefined) {
return other;
}
if (typeof value == 'string' || typeof other == 'string') {
value = baseToString(value);
other = baseToString(other);
} else {
value = baseToNumber(value);
other = baseToNumber(other);
}
result = operator(value, other);
}
return result;
};
}
/**
* Creates a function like `_.over`.
*
@@ -4727,6 +4796,23 @@
};
}
/**
* Creates a function that performs a relational operation on two values.
*
* @private
* @param {Function} operator The function to perform the operation.
* @returns {Function} Returns the new relational operation function.
*/
function createRelationalOperation(operator) {
return function(value, other) {
if (!(typeof value == 'string' && typeof other == 'string')) {
value = toNumber(value);
other = toNumber(other);
}
return operator(value, other);
};
}
/**
* Creates a function that wraps `func` to continue currying.
*
@@ -5544,7 +5630,7 @@
*/
function isKey(value, object) {
var type = typeof value;
if (type == 'number' || type == 'symbol') {
if (type == 'number' || type == 'boolean' || type == 'symbol' || value == null) {
return true;
}
return !isArray(value) &&
@@ -5561,8 +5647,8 @@
*/
function isKeyable(value) {
var type = typeof value;
return type == 'number' || type == 'boolean' ||
(type == 'string' && value != '__proto__') || value == null;
return type == 'number' || type == 'boolean' || type == 'symbol' || value == null ||
(type == 'string' && value != '__proto__');
}
/**
@@ -5813,8 +5899,8 @@
* @param {*} value The value to inspect.
* @returns {string|symbol} Returns the key.
*/
function toKey(key) {
return (typeof key == 'string' || isSymbol(key)) ? key : (key + '');
function toKey(value) {
return (typeof value == 'string' || isSymbol(value)) ? value : (value + '');
}
/**
@@ -6839,8 +6925,13 @@
var pullAt = rest(function(array, indexes) {
indexes = baseFlatten(indexes, 1);
var result = baseAt(array, indexes);
basePullAt(array, indexes.sort(compareAscending));
var length = array ? array.length : 0,
result = baseAt(array, indexes);
basePullAt(array, arrayMap(indexes, function(index) {
return isIndex(index, length) ? +index : index;
}).sort(compareAscending));
return result;
});
@@ -10253,9 +10344,7 @@
* _.gt(1, 3);
* // => false
*/
function gt(value, other) {
return value > other;
}
var gt = createRelationalOperation(baseGt);
/**
* Checks if `value` is greater than or equal to `other`.
@@ -10279,9 +10368,9 @@
* _.gte(1, 3);
* // => false
*/
function gte(value, other) {
var gte = createRelationalOperation(function(value, other) {
return value >= other;
}
});
/**
* Checks if `value` is likely an `arguments` object.
@@ -11331,9 +11420,7 @@
* _.lt(3, 1);
* // => false
*/
function lt(value, other) {
return value < other;
}
var lt = createRelationalOperation(baseLt);
/**
* Checks if `value` is less than or equal to `other`.
@@ -11357,9 +11444,9 @@
* _.lte(3, 1);
* // => false
*/
function lte(value, other) {
var lte = createRelationalOperation(function(value, other) {
return value <= other;
}
});
/**
* Converts `value` to an array.
@@ -11497,8 +11584,9 @@
if (typeof value == 'number') {
return value;
}
if (isSymbol(value)) {
return NAN;
var result = baseToNumber(value);
if (result !== result) {
return result;
}
if (isObject(value)) {
var other = isFunction(value.valueOf) ? value.valueOf() : value;
@@ -11592,17 +11680,10 @@
* // => '1,2,3'
*/
function toString(value) {
// Exit early for strings to avoid a performance hit in some environments.
if (typeof value == 'string') {
return value;
}
if (value == null) {
return '';
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : '';
}
var result = (value + '');
var result = baseToString(value);
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
@@ -15195,7 +15276,7 @@
*/
function max(array) {
return (array && array.length)
? baseExtremum(array, identity, gt)
? baseExtremum(array, identity, baseGt)
: undefined;
}
@@ -15225,7 +15306,7 @@
*/
function maxBy(array, iteratee) {
return (array && array.length)
? baseExtremum(array, getIteratee(iteratee), gt)
? baseExtremum(array, getIteratee(iteratee), baseGt)
: undefined;
}
@@ -15295,7 +15376,7 @@
*/
function min(array) {
return (array && array.length)
? baseExtremum(array, identity, lt)
? baseExtremum(array, identity, baseLt)
: undefined;
}
@@ -15325,7 +15406,7 @@
*/
function minBy(array, iteratee) {
return (array && array.length)
? baseExtremum(array, getIteratee(iteratee), lt)
? baseExtremum(array, getIteratee(iteratee), baseLt)
: undefined;
}