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; 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 * The base implementation of methods like `_.find` and `_.findKey`, without
* support for iteratee shorthands, which iterates over `collection` using * support for iteratee shorthands, which iterates over `collection` using
@@ -1017,79 +988,6 @@
return (value && value.Object === Object) ? value : null; 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`. * Gets the number of `placeholder` occurrences in `array`.
* *
@@ -1110,29 +1008,6 @@
return result; 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. * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
* *
@@ -2613,6 +2488,35 @@
return result; 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. * The base implementation of `_.fill` without an iteratee call guard.
* *
@@ -2795,6 +2699,19 @@
: arrayPush(result, symbolsFunc(object)); : 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. * 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. * The base implementation of `_.map` without support for iteratee shorthands.
* *
@@ -3667,7 +3597,8 @@
var mid = (low + high) >>> 1, var mid = (low + high) >>> 1,
computed = array[mid]; computed = array[mid];
if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) { if (computed !== null && !isSymbol(computed) &&
(retHighest ? (computed <= value) : (computed < value))) {
low = mid + 1; low = mid + 1;
} else { } else {
high = mid; high = mid;
@@ -3698,21 +3629,26 @@
high = array ? array.length : 0, high = array ? array.length : 0,
valIsNaN = value !== value, valIsNaN = value !== value,
valIsNull = value === null, valIsNull = value === null,
valIsUndef = value === undefined; valIsSymbol = isSymbol(value),
valIsUndefined = value === undefined;
while (low < high) { while (low < high) {
var mid = nativeFloor((low + high) / 2), var mid = nativeFloor((low + high) / 2),
computed = iteratee(array[mid]), computed = iteratee(array[mid]),
isDef = computed !== undefined, othIsDefined = computed !== undefined,
isReflexive = computed === computed; othIsNull = computed === null,
othIsReflexive = computed === computed,
othIsSymbol = isSymbol(computed);
if (valIsNaN) { if (valIsNaN) {
var setLow = isReflexive || retHighest; var setLow = retHighest || othIsReflexive;
} else if (valIsUndefined) {
setLow = othIsReflexive && (retHighest || othIsDefined);
} else if (valIsNull) { } else if (valIsNull) {
setLow = isReflexive && isDef && (retHighest || computed != null); setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
} else if (valIsUndef) { } else if (valIsSymbol) {
setLow = isReflexive && (retHighest || isDef); setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
} else if (computed == null) { } else if (othIsNull || othIsSymbol) {
setLow = false; setLow = false;
} else { } else {
setLow = retHighest ? (computed <= value) : (computed < value); setLow = retHighest ? (computed <= value) : (computed < value);
@@ -3767,6 +3703,27 @@
return result; 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. * The base implementation of `_.uniqBy` without support for iteratee shorthands.
* *
@@ -4102,6 +4059,85 @@
return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); 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, * Creates an array that is the composition of partially applied arguments,
* placeholders, and provided arguments into a single array of 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`. * 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. * Creates a function that wraps `func` to continue currying.
* *
@@ -5544,7 +5630,7 @@
*/ */
function isKey(value, object) { function isKey(value, object) {
var type = typeof value; var type = typeof value;
if (type == 'number' || type == 'symbol') { if (type == 'number' || type == 'boolean' || type == 'symbol' || value == null) {
return true; return true;
} }
return !isArray(value) && return !isArray(value) &&
@@ -5561,8 +5647,8 @@
*/ */
function isKeyable(value) { function isKeyable(value) {
var type = typeof value; var type = typeof value;
return type == 'number' || type == 'boolean' || return type == 'number' || type == 'boolean' || type == 'symbol' || value == null ||
(type == 'string' && value != '__proto__') || value == null; (type == 'string' && value != '__proto__');
} }
/** /**
@@ -5813,8 +5899,8 @@
* @param {*} value The value to inspect. * @param {*} value The value to inspect.
* @returns {string|symbol} Returns the key. * @returns {string|symbol} Returns the key.
*/ */
function toKey(key) { function toKey(value) {
return (typeof key == 'string' || isSymbol(key)) ? key : (key + ''); return (typeof value == 'string' || isSymbol(value)) ? value : (value + '');
} }
/** /**
@@ -6839,8 +6925,13 @@
var pullAt = rest(function(array, indexes) { var pullAt = rest(function(array, indexes) {
indexes = baseFlatten(indexes, 1); indexes = baseFlatten(indexes, 1);
var result = baseAt(array, indexes); var length = array ? array.length : 0,
basePullAt(array, indexes.sort(compareAscending)); result = baseAt(array, indexes);
basePullAt(array, arrayMap(indexes, function(index) {
return isIndex(index, length) ? +index : index;
}).sort(compareAscending));
return result; return result;
}); });
@@ -10253,9 +10344,7 @@
* _.gt(1, 3); * _.gt(1, 3);
* // => false * // => false
*/ */
function gt(value, other) { var gt = createRelationalOperation(baseGt);
return value > other;
}
/** /**
* Checks if `value` is greater than or equal to `other`. * Checks if `value` is greater than or equal to `other`.
@@ -10279,9 +10368,9 @@
* _.gte(1, 3); * _.gte(1, 3);
* // => false * // => false
*/ */
function gte(value, other) { var gte = createRelationalOperation(function(value, other) {
return value >= other; return value >= other;
} });
/** /**
* Checks if `value` is likely an `arguments` object. * Checks if `value` is likely an `arguments` object.
@@ -11331,9 +11420,7 @@
* _.lt(3, 1); * _.lt(3, 1);
* // => false * // => false
*/ */
function lt(value, other) { var lt = createRelationalOperation(baseLt);
return value < other;
}
/** /**
* Checks if `value` is less than or equal to `other`. * Checks if `value` is less than or equal to `other`.
@@ -11357,9 +11444,9 @@
* _.lte(3, 1); * _.lte(3, 1);
* // => false * // => false
*/ */
function lte(value, other) { var lte = createRelationalOperation(function(value, other) {
return value <= other; return value <= other;
} });
/** /**
* Converts `value` to an array. * Converts `value` to an array.
@@ -11497,8 +11584,9 @@
if (typeof value == 'number') { if (typeof value == 'number') {
return value; return value;
} }
if (isSymbol(value)) { var result = baseToNumber(value);
return NAN; if (result !== result) {
return result;
} }
if (isObject(value)) { if (isObject(value)) {
var other = isFunction(value.valueOf) ? value.valueOf() : value; var other = isFunction(value.valueOf) ? value.valueOf() : value;
@@ -11592,17 +11680,10 @@
* // => '1,2,3' * // => '1,2,3'
*/ */
function toString(value) { function toString(value) {
// Exit early for strings to avoid a performance hit in some environments.
if (typeof value == 'string') {
return value;
}
if (value == null) { if (value == null) {
return ''; return '';
} }
if (isSymbol(value)) { var result = baseToString(value);
return symbolToString ? symbolToString.call(value) : '';
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
} }
@@ -15195,7 +15276,7 @@
*/ */
function max(array) { function max(array) {
return (array && array.length) return (array && array.length)
? baseExtremum(array, identity, gt) ? baseExtremum(array, identity, baseGt)
: undefined; : undefined;
} }
@@ -15225,7 +15306,7 @@
*/ */
function maxBy(array, iteratee) { function maxBy(array, iteratee) {
return (array && array.length) return (array && array.length)
? baseExtremum(array, getIteratee(iteratee), gt) ? baseExtremum(array, getIteratee(iteratee), baseGt)
: undefined; : undefined;
} }
@@ -15295,7 +15376,7 @@
*/ */
function min(array) { function min(array) {
return (array && array.length) return (array && array.length)
? baseExtremum(array, identity, lt) ? baseExtremum(array, identity, baseLt)
: undefined; : undefined;
} }
@@ -15325,7 +15406,7 @@
*/ */
function minBy(array, iteratee) { function minBy(array, iteratee) {
return (array && array.length) return (array && array.length)
? baseExtremum(array, getIteratee(iteratee), lt) ? baseExtremum(array, getIteratee(iteratee), baseLt)
: undefined; : undefined;
} }