最近在看
lodash
的源码, 因此顺便记录一些文档看成学习笔记, 写的很差还请见谅哈git
github仓库 , 第一篇先从比较见到的
Math
部分开始!github
参数
augend (number): 相加的第一个数。
addend (number): 相加的第二个数。
返回
(number): 返回总和。
复制代码
_.add
函数源码以下, 能够很清楚的看到这个函数是由 createMathOperation
这个函数生成的, 第一个参数是一个函数, 这个函数有两个参数, 根据参数名称, 能够猜到是两个传入的要相加的数, 而后返回这两个数的和, 第二个参数是一个写死的 0
const add = createMathOperation((augend, addend) => augend + addend, 0)
复制代码
function createMathOperation(operator, defaultValue) {
return (value, other) => {
// 缺失参数的状况
if (value === undefined && other === undefined) {
return defaultValue
}
if (value !== undefined && other === undefined) {
return value
}
if (other !== undefined && value === undefined) {
return other
}
if (typeof value === 'string' || typeof other === 'string') {
value = baseToString(value)
other = baseToString(other)
}
else {
value = baseToNumber(value)
other = baseToNumber(other)
}
return operator(value, other)
}
}
复制代码
return
了一个函数, 这个 return
的函数接收的两个参数就是传入的两个 加数
, 首先他对参数的数量是否合法进行了分类, 若是两个参数都没有, 直接返回 deafaultValue
也就是 0
, 若是只有一个参数, 那么就直接返回了另外一个参数, 若是参数的数量是合法的, 他会先判断参数是不是字符串, 只要有一个是, 会经过 baseToString
将其所有转成字符串, 若是参数中并无字符串, 经过 baseToNumber
确保转成数值, 最后执行第一个传入的 operator
, 最后返回的是传入的 operator(value, other)
, 这下咱们明白了, operator
是规定运算的种类, 由于当前是 _.add
因此传入的 operator
是 (augend, addend) => augend + addend
, 一样的对四则运算均可以进行扩展, 上述用到了两个转换类型的函数 baseToString
和 baseToNumber
, 咱们来看一下他们都作了什么typeof
判断是否是一个 number
类型, 若是是, 不须要转symbol
类型, 若是是 symbol
类型不能转成 number
, 直接返回 NaN
+value
const NAN = 0 / 0
function baseToNumber(value) {
if (typeof value === 'number') {
return value
}
if (isSymbol(value)) {
return NAN
}
return +value
}
复制代码
typeof
判断是否是一个 string
, 若是是不须要转symbol
类型, 经过 Symbol.prototype.toString.call(value)
转成字符串1
, 使用
${1}
以后会转成字符串, 而若是是一个对象类型, 和使用 Object.prototype.call({})
同样, 返回 [Object object]
, 也就是说对于基本类型好比 数字
, 进行正常转换, 不是基本类型转成 [Object xxx]
这种形式-0
进行一个判断, 不然不管 -0
仍是 +0
都会输出 0
, 这里先是对已经转换了的结果 result
进行一个无关类型的 ==
比较, 看他是否 0
, 若是是 0
再看看是否是 -0
, 具体细节源码中展示的已经比较清楚了..const symbolToString = Symbol.prototype.toString
const INFINITY = 1 / 0
function baseToString(value) {
if (typeof value === 'string') {
return value
}
if (Array.isArray(value)) {
return `${value.map(baseToString)}`
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : ''
}
const result = `${value}`
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result
}
复制代码
总结一下, 经过
createMathOperation(operator, defaultValue)
传入一个运算函数, 返回一个新的_.add
函数, 而且经过baseToNumber
和baseToString
进行了类型转化, 一样的另外的一些运算也能够按照相似来实现ide
参数
number (number): 要向上舍入的值。
[precision=0] (number): 向上舍入的的精度。
返回
(number): 返回向上舍入的值。
复制代码
const ceil = createRound('ceil')
复制代码
Math
对象的向上取整函数, 并保留到 func
变量return
一个新的函数, 第一个参数是将要取整的数, 第二个参数是精度
precision
参数, 若是没有初始化成 0
, 即不保留精度科学记数法
先转成一个大数, 而后对其使用 func
取整, 再用用 科学记数法
转成该精度的小数
6.004
, 要求精度是 2
6.004 e 2 => 600.4
func(601)
601 e -2 => 6.01
function createRound(methodName) {
const func = Math[methodName]
return (number, precision) => {
precision = precision == null ? 0 : (precision >= 0 ? Math.min(precision, 292) : Math.max(precision, -292))
if (precision) {
let pair = `${number}e` .split('e')
const value = func( `${pair[0]}e${+pair[1] + precision}` )
pair = `${value}e` .split('e')
return + `${pair[0]}e${+pair[1] - precision}`
}
return func(number)
}
}
复制代码
类似的, 能够实现
向下取整
,四舍五入取整
, 只要在最开始获取Math
的原生方法不同便可函数
参数
array (Array): 要迭代的数组。
[iteratee=_.identity] (Function): 调用每一个元素的迭代函数。
返回
(number): 返回平均值。
复制代码
baseSum
算出总和再除一下const NAN = 0 / 0
function meanBy(array, iteratee) {
const length = array == null ? 0 : array.length
return length ? (baseSum(array, iteratee) / length) : NAN
}
复制代码
for of
遍历数组, 对每一项执行传入的 iteratee
, 而后累加function baseSum(array, iteratee) {
let result
for (const value of array) {
const current = iteratee(value)
if (current !== undefined) {
result = result === undefined ? current : (result + current)
}
}
return result
}
复制代码