JavaScript實用庫:Lodash源碼數組函數解析(六)first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable

本章的內容主要是:first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable


在這裏插入圖片描述

Lodash是一個非常好用方便的JavaScript的工具庫,使得我們對數據處理能夠更加得心應手

接下來我要對Lodash的源碼進行剖析學習
每天幾個小方法,跟着我一起來學lodash吧


1、_.first -> _.head(array)

根據lodash中文文檔介紹,通過該方法可以獲取到數組的第一個元素

可以看到啊,它有兩個名詞:firsthead

我們來看它的例子:
在這裏插入圖片描述

例子也很通俗易懂啊,這裏我就不多說了

接下來看源碼:

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


今天就到這裏了,明天繼續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章