最近在看
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
}
複製代碼