_.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;

 

 

posted @ 2018-12-10 10:55  hahazexia  阅读(442)  评论(0)    收藏  举报