lodash源码学习(13)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lodash源码学习(13)相关的知识,希望对你有一定的参考价值。

继续学习lodash,math部分,也就是一些数学相关的方法

“Math” Methods

_.add(augend, addend)

加法函数.
//add.js
var createMathOperation = require(‘./_createMathOperation‘); //包装方法

/**
 * 
 *
 * @param {number} augend 相加的第一个值.
 * @param {number} addend 相加的第二个值.
 * @returns {number} 返回总值.
 * @example
 *
 * _.add(6, 4);
 * // => 10
 */
var add = createMathOperation(function(augend, addend) {// 调用createMathOperation
  return augend + addend;
}, 0);

module.exports = add;

依赖于包装方法createMathOperation

//.createMathOperation.js

var baseToNumber = require(‘./_baseToNumber‘), //转化为数字
    baseToString = require(‘./_baseToString‘); //转化为字符串

/**
 * 闯将一个方法对两个值进行数学操作.
 *
 * @private
 * @param {Function} operator 需要进行的操作函数.
 * @param {number} [defaultValue] 默认结果值.
 * @returns {Function} 返回新的操作方法.
 * 
 */
function createMathOperation(operator, defaultValue) {
  return function(value, other) {
    var result;
    if (value === undefined && other === undefined) { //如果没有传参,返回默认值
      return defaultValue;
    }
    if (value !== undefined) {
      result = value;
    }
    if (other !== undefined) {
      if (result === undefined) {//如果第一个参数为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;// 返回执行结果
  };
}

module.exports = createMathOperation;

减法,乘法,除法也是基于这个方法而来的

_.divide(dividend, divisor)

两个数值相除
//divide.js

var createMathOperation = require(‘./_createMathOperation‘);//包装方法

/**
 *
 * @param {number} dividend 被除数.
 * @param {number} divisor 除数.
 * @returns {number} 返回执行结果.
 * @example
 *
 * _.divide(6, 4);
 * // => 1.5
 */
var divide = createMathOperation(function(dividend, divisor) { //和add方法类似
  return dividend / divisor;
}, 1);

module.exports = divide;

 

_.multiply(multiplier, multiplicand)

两个数值想乘.
//multiply.js

var createMathOperation = require(‘./_createMathOperation‘);

/**
 *
 * @param {number} multiplier 相乘的第一个值.
 * @param {number} multiplicand 相乘的第二个值.
 * @returns {number} 返回执行结果.
 * @example
 *
 * _.multiply(6, 4);
 * // => 24
 */
var multiply = createMathOperation(function(multiplier, multiplicand) {//和add方法类似
  return multiplier * multiplicand;
}, 1);

module.exports = multiply;

_.subtract(minuend, subtrahend)

两个数值相减.
//subtract.js

var createMathOperation = require(‘./_createMathOperation‘);

/**
 *
 * @param {number} minuend 被减数.
 * @param {number} subtrahend 减数.
 * @returns {number} 返回执行结果.
 * @example
 *
 * _.subtract(6, 4);
 * // => 2
 */
var subtract = createMathOperation(function(minuend, subtrahend) {//和add方法类似
  return minuend - subtrahend;
}, 0);

module.exports = subtract;

_.ceil(number, [precision=0])

对数值进行上舍入.
//ceil.js

var createRound = require(‘./_createRound‘); //约数构造器

/**
 *
 * @static
 * @memberOf _
 * @since 3.10.0
 * @category Math
 * @param {number} number 需要处理的数字.
 * @param {number} [precision=0] 精确的位数.
 * @returns {number} 返回舍入之后的数值.
 * @example
 *
 * _.ceil(4.006);
 * // => 5
 *
 * _.ceil(6.004, 2);
 * // => 6.01
 *
 * _.ceil(6040, -2);
 * // => 6100
 */
var ceil = createRound(‘ceil‘); //调用createRound,传入ceil

module.exports = ceil;

这个方法依赖于createRound方法

//_createRound.js

var toInteger = require(‘./toInteger‘), //转化为整型
    toNumber = require(‘./toNumber‘), //转化为数字
    toString = require(‘./toString‘); //转化为字符串

/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeMin = Math.min;

/**
 * 创建一个约数方法.
 *
 * @private
 * @param {string} methodName 在Math方法中对应的方法名.
 * @returns {Function} 返回新的约数方法.
 */
function createRound(methodName) {
  var func = Math[methodName]; //对应方法
  return function(number, precision) {
    number = toNumber(number); //转化为数字
    precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
    if (precision) {
      //用指数表示避免浮点问题
      var pair = (toString(number) + ‘e‘).split(‘e‘),
          value = func(pair[0] + ‘e‘ + (+pair[1] + precision));//先扩大10的precision倍,再调用func方法

      pair = (toString(value) + ‘e‘).split(‘e‘);
      return +(pair[0] + ‘e‘ + (+pair[1] - precision));//缩小10的precision倍,还原数值
    }
    return func(number);
  };
}

module.exports = createRound;

既然有ceil方法,那就必然有floor和round方法

_.floor(number, [precision=0])

对一个数值进行下舍入.
//floor.js

var createRound = require(‘./_createRound‘);

/**
 *
 * @param {number} number 需要处理的数值.
 * @param {number} [precision=0] 精确的位数.
 * @returns {number} 返回处理后的数值.
 * @example
 *
 * _.floor(4.006);
 * // => 4
 *
 * _.floor(0.046, 2);
 * // => 0.04
 *
 * _.floor(4060, -2);
 * // => 4000
 */
var floor = createRound(‘floor‘);//调用createRound,传入floor

module.exports = floor;

_.round(number, [precision=0])

对一个数值进行四舍五入.
//round.js

var createRound = require(‘./_createRound‘);

/**
 *
 * @param {number} number 需要处理的数值.
 * @param {number} [precision=0] 精确的位数.
 * @returns {number} 返回处理之后的数值.
 * @example
 *
 * _.round(4.006);
 * // => 4
 *
 * _.round(4.006, 2);
 * // => 4.01
 *
 * _.round(4060, -2);
 * // => 4100
 */
var round = createRound(‘round‘);//调用createRound,传入round

module.exports = round;

_.max(array)

计算数组中的最大值.
 
//max.js

var baseExtremum = require(‘./_baseExtremum‘), //基础求极值方法
    baseGt = require(‘./_baseGt‘), //大于比较方法,baseGt(3,1) => true, baseGt(3, 4) => false
    identity = require(‘./identity‘); //返回第一个参数

/**
 *
 * @param {Array} array 需要处理的数组.
 * @returns {*} 返回数组中的最大值.
 * @example
 *
 * _.max([4, 2, 8, 6]);
 * // => 8
 *
 * _.max([]);
 * // => undefined
 */
function max(array) {
  return (array && array.length)
    ? baseExtremum(array, identity, baseGt) //调用baseExtremum方法
    : undefined;
}

module.exports = max;

依赖于baseExtremum方法

//_baseExtremum.js

var isSymbol = require(‘./isSymbol‘);

/**
 * max和min的基本实现,接受一个比较方法决定这个极值
 *
 * @private
 * @param {Array} array 需要处理的数组.
 * @param {Function} iteratee 对每个元素调用的迭代器.
 * @param {Function} comparator 比较两个值得比较方法.
 * @returns {*} 返回这个极值.
 */
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;//返回对应的元素
}

module.exports = baseExtremum;

_.min(array)

计算数组中的最小值.
//min.js

var baseExtremum = require(‘./_baseExtremum‘),
    baseLt = require(‘./_baseLt‘),//小于比较方法,baseGt(3,1) => false, baseGt(3, 4) => true
    identity = require(‘./identity‘);

/**
 *
 * @param {Array} 需要处理的数组.
 * @returns {*} 返回最小值.
 * @example
 *
 * _.min([4, 2, 8, 6]);
 * // => 2
 *
 * _.min([]);
 * // => undefined
 */
function min(array) {
  return (array && array.length)
    ? baseExtremum(array, identity, baseLt)
    : undefined;
}

module.exports = min;

_.maxBy(array, [iteratee=_.identity])

和max方法很像,除了它接受一个遍历方法对每个元素调用,生成用于比较的值,遍历方法接受一个参数:value.
//maxBy.js

var baseExtremum = require(‘./_baseExtremum‘),
    baseGt = require(‘./_baseGt‘),
    baseIteratee = require(‘./_baseIteratee‘); //基础遍历方法,支持熟悉简写

/**
 * 
 *
 * @param {Array} array 需要处理的数组.
 * @param {Function} [iteratee=_.identity] 遍历方法.
 * @returns {*} 返回对应的最大值.
 * @example
 *
 * var objects = [{ ‘n‘: 1 }, { ‘n‘: 2 }];
 *
 * _.maxBy(objects, function(o) { return o.n; });
 * // => { ‘n‘: 2 }
 *
 * // The `_.property` iteratee shorthand.
 * _.maxBy(objects, ‘n‘);
 * // => { ‘n‘: 2 }
 */
function maxBy(array, iteratee) { 
  return (array && array.length)
    ? baseExtremum(array, baseIteratee(iteratee, 2), baseGt) //调用baseExtremum,并且传入遍历方法,和大于比较方法
    : undefined;
}

module.exports = maxBy;

_.minBy(array, [iteratee=_.identity])

和max方法很像,除了它接受一个遍历方法对每个元素调用,生成用于比较的值,遍历方法接受一个参数:value.
//minBy.js

var baseExtremum = require(‘./_baseExtremum‘),
    baseIteratee = require(‘./_baseIteratee‘),
    baseLt = require(‘./_baseLt‘);

/**
 * 
 *
 * @param {Array} array 需要处理的数组.
 * @param {Function} [iteratee=_.identity] 遍历方法.
 * @returns {*} 返回对应的最小值.
 * @example
 *
 * var objects = [{ ‘n‘: 1 }, { ‘n‘: 2 }];
 *
 * _.minBy(objects, function(o) { return o.n; });
 * // => { ‘n‘: 1 }
 *
 * // The `_.property` iteratee shorthand.
 * _.minBy(objects, ‘n‘);
 * // => { ‘n‘: 1 }
 */
function minBy(array, iteratee) {
  return (array && array.length)
    ? baseExtremum(array, baseIteratee(iteratee, 2), baseLt) //调用baseExtremum,并且传入遍历方法,和小于比较方法
    : undefined;
}

module.exports = minBy;

_.sum(array)

对数组元素进行求和.
// sum.js
var baseSum = require(‘./_baseSum‘), //基础求和方法
    identity = require(‘./identity‘); //返回第一个参数

/**
 *
 * @param {Array} array 需要处理的数组.
 * @returns {number} 返回总和.
 * @example
 *
 * _.sum([4, 2, 8, 6]);
 * // => 20
 */
function sum(array) {
  return (array && array.length)
    ? baseSum(array, identity) //调用baseSum方法
    : 0;
}

module.exports = sum;

依赖于baseSum方法

// _baseSum.js

/**
 * 基础求和方法,不支持遍历器简写
 *
 * @private
 * @param {Array} array 需要处理的数组.
 * @param {Function} iteratee 遍历方法,对每个元素调用.
 * @returns {number} 返回总和.
 */
 function baseSum(array, iteratee) {
  var result,
      index = -1,
      length = array.length;

  while (++index < length) { //遍历数组
    var current = iteratee(array[index]); //对当前值调用遍历方法
    if (current !== undefined) {
      result = result === undefined ? current : (result + current); //执行相加
    }
  }
  return result;//返回结果
}

module.exports = baseSum;

_.sumBy(array, [iteratee=_.identity])

求和方法,和sum很像,除了它接受一个遍历方法对每个元素调用生成用于相加的方法.
//sumBy.js

var baseIteratee = require(‘./_baseIteratee‘),
    baseSum = require(‘./_baseSum‘);

/**
 *
 * @param {Array} array 需要处理的数组.
 * @param {Function} [iteratee=_.identity] 遍历方法.
 * @returns {number} 返回总和.
 * @example
 *
 * var objects = [{ ‘n‘: 4 }, { ‘n‘: 2 }, { ‘n‘: 8 }, { ‘n‘: 6 }];
 *
 * _.sumBy(objects, function(o) { return o.n; });
 * // => 20
 *
 * // The `_.property` iteratee shorthand.
 * _.sumBy(objects, ‘n‘);
 * // => 20
 */
function sumBy(array, iteratee) {
  return (array && array.length)
    ? baseSum(array, baseIteratee(iteratee, 2)) //调用baseSum方法,传入遍历器,并且支持属性简写
    : 0;
}

module.exports = sumBy;

_.mean(array)

求数组所有元素的平均值.
//mean.js

var baseMean = require(‘./_baseMean‘), //基础mean方法
    identity = require(‘./identity‘); //返回第一个参数

/**
 * 求数组所有元素的平均值.
 *
 * @param {Array} array 需要处理的数组.
 * @returns {number} 返回平均值.
 * @example
 *
 * _.mean([4, 2, 8, 6]);
 * // => 5
 */
function mean(array) {
  return baseMean(array, identity); //调用baseMean方法
}

module.exports = mean;

 

依赖于baseMean方法

//_baseMean.js

var baseSum = require(‘./_baseSum‘); //基础求和方法

/** Used as references for various `Number` constants. */
var NAN = 0 / 0;

/**
 * 基础求平均值方法,不支持遍历器的简写
 *
 * @private
 * @param {Array} array 需要处理的数组.
 * @param {Function} iteratee 遍历器对每个元素调用.
 * @returns {number} 返回平均值.
 */
function baseMean(array, iteratee) {
  var length = array == null ? 0 : array.length;
  return length ? (baseSum(array, iteratee) / length) : NAN; //调用baseSum进行求和,再进行求平均值,如果没有元素,则返回NaN
}

module.exports = baseMean;

_.meanBy(array, [iteratee=_.identity])

求平均值方法,和mean方法类似.除了它接受一个遍历方法对每个元素调用,生成用于计算的值,遍历方法接受一个参数:value.
// meanBy.js

var baseIteratee = require(‘./_baseIteratee‘),
    baseMean = require(‘./_baseMean‘);

/**
 * 求平均值方法,和mean方法类似.除了它接受一个遍历方法对每个元素调用,生成用于计算的值,遍历方法接受一个参数:value.
 *
 * @param {Array} array 需要处理的数组.
 * @param {Function} [iteratee=_.identity] 遍历器对每个元素调用。
 * @returns {number} 返回这个平均值.
 * @example
 *
 * var objects = [{ ‘n‘: 4 }, { ‘n‘: 2 }, { ‘n‘: 8 }, { ‘n‘: 6 }];
 *
 * _.meanBy(objects, function(o) { return o.n; });
 * // => 5
 *
 * // The `_.property` iteratee shorthand.
 * _.meanBy(objects, ‘n‘);
 * // => 5
 */
function meanBy(array, iteratee) {
  return baseMean(array, baseIteratee(iteratee, 2));//调用baseMean方法,传入遍历器,并且支持属性简写。
}

module.exports = meanBy;

 

以上是关于lodash源码学习(13)的主要内容,如果未能解决你的问题,请参考以下文章

lodash源码学习

lodash源码学习

lodash源码学习

lodash源码学习

lodash源码学习(10)

lodash源码学习debounce,throttle