_.spread(func, [start=0])
113
_.spread(func, [start=0])
_.spread创建一个函数会调用func函数,绑定this到新创建的函数身上并且传入一个类似apply一样的参数列表
类似于调用函数时使用展开操作符...将数组展开
参数
func (Function): 需要将参数展开传入的函数
[start=0] (number): 参数列表中需要展开的参数的位置
返回值
(Function): 返回处理好的新函数
例子
var say = _.spread(function(who, what) { return who + ' says ' + what; }); say(['fred', 'hello']); // => 'fred says hello' var numbers = Promise.all([ Promise.resolve(40), Promise.resolve(36) ]); numbers.then(_.spread(function(x, y) { return x + y; })); // => a Promise of 76
源代码:
/** * lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors <https://jquery.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** Used as the `TypeError` message for "Functions" methods. */ var FUNC_ERROR_TEXT = 'Expected a function'; /** Used as references for various `Number` constants. */ var INFINITY = 1 / 0, MAX_INTEGER = 1.7976931348623157e+308, NAN = 0 / 0; /** `Object#toString` result references. */ var symbolTag = '[object Symbol]'; /** Used to match leading and trailing whitespace. */ var reTrim = /^\s+|\s+$/g; /** Used to detect bad signed hexadecimal string values. */ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; /** Used to detect binary string values. */ var reIsBinary = /^0b[01]+$/i; /** Used to detect octal string values. */ var reIsOctal = /^0o[0-7]+$/i; /** Built-in method references without a dependency on `root`. */ var freeParseInt = parseInt; /** * A faster alternative to `Function#apply`, this function invokes `func` * with the `this` binding of `thisArg` and the arguments of `args`. * * @private * @param {Function} func The function to invoke. * @param {*} thisArg The `this` binding of `func`. * @param {Array} args The arguments to invoke `func` with. * @returns {*} Returns the result of `func`. */ //一个较快的apply function apply(func, thisArg, args) { switch (args.length) { case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case 2: return func.call(thisArg, args[0], args[1]); case 3: return func.call(thisArg, args[0], args[1], args[2]); } return func.apply(thisArg, args); } /** * Appends the elements of `values` to `array`. * * @private * @param {Array} array The array to modify. * @param {Array} values The values to append. * @returns {Array} Returns `array`. */ //将参数值添加入参数数组 function arrayPush(array, values) { var index = -1,//循环索引 length = values.length,//需要添加到源数组的参数 offset = array.length;//源数组的长度 while (++index < length) {//循环并讲参数一个一个加入源数组 array[offset + index] = values[index]; } return array; } /** Used for built-in method references. */ var objectProto = Object.prototype; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeMax = Math.max; /** * The base implementation of `_.rest` which doesn't validate or coerce arguments. * * @private * @param {Function} func The function to apply a rest parameter to. * @param {number} [start=func.length-1] The start position of the rest parameter. * @returns {Function} Returns the new function. */ //rest方法的基础实现 function baseRest(func, start) { start = nativeMax(start === undefined ? (func.length - 1) : start, 0); //处理start,如果没有start参数,start就赋值为func函数的形参个数减去1 return function() { var args = arguments,//新函数接收的参数列表 index = -1,//循环索引 length = nativeMax(args.length - start, 0),//rest参数长度 array = Array(length);//rest参数数组初始化 while (++index < length) {//循环length次数,将新函数接收到的参数插入rest参数数组中 array[index] = args[start + index]; } index = -1;//循环变量重新赋值为-1 var otherArgs = Array(start + 1);//除了rest参数之外的其他参数 while (++index < start) {//循环将除了rest参数之外的其他参数收集 otherArgs[index] = args[index]; } otherArgs[start] = array;//参数列表的最后一个参数是rest参数数组 return apply(func, this, otherArgs);//apply调用fn传递参数,返回结果 }; } /** * The base implementation of `_.slice` without an iteratee call guard. * * @private * @param {Array} array The array to slice. * @param {number} [start=0] The start position. * @param {number} [end=array.length] The end position. * @returns {Array} Returns the slice of `array`. */ //创建一个数组array的切片,从起始索引到结束索引,不包括结束索引 function baseSlice(array, start, end) { var index = -1,//循环索引 length = array.length;//数组长度 if (start < 0) {//起始索引是负数处理,是负数就相当于从末尾往开头数,也就是和lengh相加 start = -start > length ? 0 : (length + start);//和length相加后如果还是小于0就等于0 } end = end > length ? length : end;//结束索引如果大于length就让它等于length if (end < 0) {//处理结束索引是负数 end += length; } length = start > end ? 0 : ((end - start) >>> 0);//根据start和end计算这个切片的长度,如果起始在结束后面那么切片长度为0,否则相减并且取整 start >>>= 0;//start取整 var result = Array(length);//结果切片数组 while (++index < length) {//循环切片长度的次数,给结果数组每一项赋值 result[index] = array[index + start]; } return result; } /** * Casts `array` to a slice if it's needed. * * @private * @param {Array} array The array to inspect. * @param {number} start The start position. * @param {number} [end=array.length] The end position. * @returns {Array} Returns the cast slice. */ //创造一个数组的切片,从start到end元素 function castSlice(array, start, end) { var length = array.length;//数组长度 end = end === undefined ? length : end;//切片结束位置 return (!start && end >= length) ? array : baseSlice(array, start, end); //如果没有start而且end大于数组长度,直接返回array,否则调用baseSlice处理 } /** * Creates a function that invokes `func` with the `this` binding of the * create function and an array of arguments much like * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). * * **Note:** This method is based on the * [spread operator](https://mdn.io/spread_operator). * * @static * @memberOf _ * @since 3.2.0 * @category Function * @param {Function} func The function to spread arguments over. * @param {number} [start=0] The start position of the spread. * @returns {Function} Returns the new function. * @example * * var say = _.spread(function(who, what) { * return who + ' says ' + what; * }); * * say(['fred', 'hello']); * // => 'fred says hello' * * var numbers = Promise.all([ * Promise.resolve(40), * Promise.resolve(36) * ]); * * numbers.then(_.spread(function(x, y) { * return x + y; * })); * // => a Promise of 76 */ //创建一个函数会调用func函数,绑定this到新创建的函数身上并且传入一个类似apply一样的参数列表 //类似于调用函数时使用展开操作符...将数组展开 function spread(func, start) { if (typeof func != 'function') {//判断func是否是一个函数,不是抛出错误 throw new TypeError(FUNC_ERROR_TEXT); } start = start === undefined ? 0 : nativeMax(toInteger(start), 0); //start是需要展开的参数列表的起始位置,如果没有传递就是0,有start参数就调用toInteger转成整数 return baseRest(function(args) { var array = args[start],//新创建的函数接收到的rest数组参数的start位置 otherArgs = castSlice(args, 0, start);//除了需要展开的参数之外的其他参数 if (array) {//如果存在需要展开的数组,将需要展开数组push到其他参数的后面 arrayPush(otherArgs, array); } return apply(func, this, otherArgs);//返回apply调用结果 }); } /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value; return !!value && (type == 'object' || type == 'function'); } /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return !!value && typeof value == 'object'; } /** * Checks if `value` is classified as a `Symbol` primitive or object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. * @example * * _.isSymbol(Symbol.iterator); * // => true * * _.isSymbol('abc'); * // => false */ function isSymbol(value) { return typeof value == 'symbol' || (isObjectLike(value) && objectToString.call(value) == symbolTag); } /** * Converts `value` to a finite number. * * @static * @memberOf _ * @since 4.12.0 * @category Lang * @param {*} value The value to convert. * @returns {number} Returns the converted number. * @example * * _.toFinite(3.2); * // => 3.2 * * _.toFinite(Number.MIN_VALUE); * // => 5e-324 * * _.toFinite(Infinity); * // => 1.7976931348623157e+308 * * _.toFinite('3.2'); * // => 3.2 */ //将一个值转换成 有限 的数字 function toFinite(value) { if (!value) {//如果value为假,返回0 return value === 0 ? value : 0; } value = toNumber(value);//将value转换成number类型 if (value === INFINITY || value === -INFINITY) {//如果是无限 var sign = (value < 0 ? -1 : 1);//正负标记 return sign * MAX_INTEGER;//转换成有限值 } return value === value ? value : 0;//返回结果,如果是NaN就返回0 } /** * Converts `value` to an integer. * * **Note:** This method is loosely based on * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to convert. * @returns {number} Returns the converted integer. * @example * * _.toInteger(3.2); * // => 3 * * _.toInteger(Number.MIN_VALUE); * // => 0 * * _.toInteger(Infinity); * // => 1.7976931348623157e+308 * * _.toInteger('3.2'); * // => 3 */ //将一个值转换成整数 function toInteger(value) { var result = toFinite(value),//将value转换成有限值 remainder = result % 1;//取余获取到小数部分 return result === result ? (remainder ? result - remainder : result) : 0; //如果是NaN返回0,如果是小数,减去小数部分,如果没有小数部分直接返回 } /** * Converts `value` to a number. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {number} Returns the number. * @example * * _.toNumber(3.2); * // => 3.2 * * _.toNumber(Number.MIN_VALUE); * // => 5e-324 * * _.toNumber(Infinity); * // => Infinity * * _.toNumber('3.2'); * // => 3.2 */ //将一个值转换成数字 function toNumber(value) { if (typeof value == 'number') {//如果是number直接返回 return value; } if (isSymbol(value)) {//如果是Symbol类型,返回NaN return NAN; } if (isObject(value)) {//如果value是对象 var other = typeof value.valueOf == 'function' ? value.valueOf() : value; //如果value有valueOf属性,就调用valueOf()取值,否则取原值 value = isObject(other) ? (other + '') : other; //如果other是对象,就转成字符串,否则取原值 } if (typeof value != 'string') {//value被转成字符串后的处理 return value === 0 ? value : +value; } value = value.replace(reTrim, '');//正则把空白字符都转换成空字符串 var isBinary = reIsBinary.test(value);//判断是否是二进制 return (isBinary || reIsOctal.test(value)) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : (reIsBadHex.test(value) ? NAN : +value); //如果是二进制或者八进制,调用parseInt转换 //否则判断不良签名的十六进制转为NaN } module.exports = spread;

浙公网安备 33010602011771号