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