本章的內容主要是:first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable
Lodash是一個非常好用方便的JavaScript的工具庫,使得我們對數據處理能夠更加得心應手
接下來我要對Lodash的源碼進行剖析學習
每天幾個小方法,跟着我一起來學lodash吧
1、_.first -> _.head(array)
根據lodash中文文檔介紹,通過該方法可以獲取到數組的第一個元素
可以看到啊,它有兩個名詞:first 和 head
我們來看它的例子:
例子也很通俗易懂啊,這裏我就不多說了
接下來看源碼:
function head(array) {
//數組不爲空則輸出數組第一個元素
return (array && array.length) ? array[0] : undefined;
}
module.exports = head;
還好,源碼很簡單
2、_.flatten(array)
根據中文文檔介紹:減少一級array嵌套深度
看到這個我們就立馬想起了扁平化數組核心函數:baseFlatten,可能源碼中都是基於它來實現的
下面直接來看例子啊
就一個例子,還挺容易懂的,發現在數組內部少了一個嵌套
那麼這是怎麼來實現的呢?下面看源碼:
function flatten(array) {
//獲取數組的長度
var length = array == null ? 0 : array.length;
//數組長度爲0輸出空數組
//不爲0則使用baseFlatten函數向下扁平化1層
return length ? baseFlatten(array, 1) : [];
}
module.exports = flatten;
源碼不多,果然是基於baseFlatten來實現的
有了這個核心函數還是很容易實現這個功能的
3、_.flattenDeep(array)
根據中文文檔介紹,該方法能夠將數組化爲一維數組,也就是說無論嵌套多少層都能化爲一維數組
下面我們來看例子:
也是一個簡簡單單的例子,希望源碼也那麼簡單
下面我們來看源碼:
/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0;
/**
* Recursively flattens `array`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to flatten.
* @returns {Array} Returns the new flattened array.
* @example
*
* _.flattenDeep([1, [2, [3, [4]], 5]]);
* // => [1, 2, 3, 4, 5]
*/
function flattenDeep(array) {
var length = array == null ? 0 : array.length;
return length ? baseFlatten(array, INFINITY) : [];
}
module.exports = flattenDeep;
它的實現與flatten明明一模一樣,爲什麼能夠化爲一維數組呢,因爲我們定義的變量INFINITY的值是 1 / 0,這個值位於baseFlatten函數的第二個參數位時意味着展開層數無限,所以能化爲一維數組啦
4、_.flattenDepth(array, [depth=1])
這個方法和前面兩個差不多,但是該方法的第二個參數是能夠指定層級的,默認爲0,當第二個值沒有時,該方法就和flatten是一樣的了
我們接下來看例子;
這個我也不多說了,還是挺容易理解的
接下來我們看源碼是怎麼實現的:
function flattenDepth(array, depth) {
//獲取數組長度
var length = array == null ? 0 : array.length;
//數組長度爲0則輸出空數組
if (!length) {
return [];
}
//確定depth的值
//當depth的值沒有定義時,賦值爲1
//當有定義時賦值傳入值的整數值
depth = depth === undefined ? 1 : toInteger(depth);
//扁平化數組
return baseFlatten(array, depth);
}
module.exports = flattenDepth;
該方法還是基於baseFlatten的扁平化方法
既然這樣,我覺得有必要再提及一次這個核心函數
5、baseFlatten
因爲中文文檔沒有介紹,所以我們只能直接看源碼了
/**
* The base implementation of `flatten` with support for restricting flattening.
*
* @private
* @param {Array} array The array to flatten.
* @param {number} depth The maximum recursion depth.
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
* @param {Array} [result=[]] The initial result value.
* @returns {Array} Returns the new flattened array.
*/
//這個方法用於數組展開
//array需要展開操作的數組,depth需要展開的層數
//predicate用於判斷值是否可展開
//isStrict標識用於判斷是否約束值必須通過predicate方法的檢查
function baseFlatten(array, depth, predicate, isStrict, result) {
predicate || (predicate = isFlattenable)//predicate每次循環都會調用,用來判斷當前值是否是一個可展開的array-like對象
result || (result = [])
if (array == null) {//需要展開的數組是空,就返回空數組
return result
}
for (const value of array) {
if (depth > 0 && predicate(value)) {//如果展開層數大於0且當前循環值可展開
if (depth > 1) {//如果展開層數大於一層就繼續遞歸調用,層數減一
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result)
} else {//如果只展開一層,就展開後push到result裏
result.push(...value)
}
} else if (!isStrict) {//如果沒有傳遞isStrict標識,就直接將當前循環值push入結果數組
result[result.length] = value
}
}
return result
}
export default baseFlatten
實現過程還是稍微比較複雜的
既然到了這裏,還有一個函數我覺得也可以一併說一下:isFlattenable
6、isFlattenable
很遺憾,文檔裏面也沒有介紹
該方法的功能是:檢查一個變量是否是一個可展開的對象或者數組
接下來我們看源碼:
/** Built-in value reference. */
const spreadableSymbol = Symbol.isConcatSpreadable
/**
* Checks if `value` is a flattenable `arguments` object or array.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
*/
function isFlattenable(value) {
return Array.isArray(value) || isArguments(value) ||
!!(spreadableSymbol && value && value[spreadableSymbol])
//如果是數組,則可展開
//如果是arguments對象,則可展開
//如果當前環境含有Symbol對象,且此變量含有Symbol.isConcatSpreadable屬性,Symbol.isConcatSpreadable用於改變array或者array-like對象使用concat時的默認行爲
}
export default isFlattenable
如果可展開則輸出true,反之false
今天就到這裏了,明天繼續