_.rest(func, [start=func.length-1])

112

_.rest(func, [start=func.length-1])
rest参数的实现
创建一个函数,在调用func函数的时候将this绑定到这个新创建的函数上,并且参数列表从start开始之后的参数被提供为一个参数数组

参数

func (Function): 需要将其参数列表重新整理的函数
indexes (...(number|number[])): 重新整理参数的索引数组

返回值

(Function): 返回处理好的新函数

例子

var say = _.rest(function(what, names) {
  return what + ' ' + _.initial(names).join(', ') +
    (_.size(names) > 1 ? ', & ' : '') + _.last(names);
});
 
say('hello', 'fred', 'barney', 'pebbles');
// => 'hello fred, barney, & pebbles'

源代码

/**
 * 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);
}

/** 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传递参数,返回结果
  };
}

/**
 * Creates a function that invokes `func` with the `this` binding of the
 * created function and arguments from `start` and beyond provided as
 * an array.
 *
 * **Note:** This method is based on the
 * [rest parameter](https://mdn.io/rest_parameters).
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Function
 * @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.
 * @example
 *
 * var say = _.rest(function(what, names) {
 *   return what + ' ' + _.initial(names).join(', ') +
 *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
 * });
 *
 * say('hello', 'fred', 'barney', 'pebbles');
 * // => 'hello fred, barney, & pebbles'
 */
//rest参数的实现
//创建一个函数,在调用func函数的时候将this绑定到这个新创建的函数上,并且参数列表从start开始之后的参数被提供为一个参数数组
function rest(func, start) {
  if (typeof func != 'function') {//如果func不是函数,抛出错误
    throw new TypeError(FUNC_ERROR_TEXT);
  }
  start = start === undefined ? start : toInteger(start);//如果有start参数,转换成整数,如果没有保持为undefined
  return baseRest(func, start);//调用baseRest处理
}

/**
 * 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
 */
//判断一个值是否是一个object-like对象
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
 */
//判断一个值是否是一个symbol对象
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 = rest;

 

posted @ 2018-12-06 22:56  hahazexia  阅读(236)  评论(0)    收藏  举报