陪你去看 Lodash.js 起步

lodash 起步(數組)

Lodash 是一個較為流行的 JavaScript 的實用工具庫。

在開發過程中如果能熟練使用一些工具庫提供的方法,有利於提高開發效率

筆者從 API 上入手,不分析其源碼,先從全局的角度來體驗、研究它。分析 API 的命名特性、哪些方法有用,哪些又是比較雞肋,僅代表筆者個人意見。

Tip:根據Lodash 中文文檔得知,API 主要分為:數組、集合、函數、語言、數學、數字、對象、Seq、字元串、實用函數等約10個部分。而數組在我們編程過程中具有非常重要的地位,故筆者決定先從其入手。

環境準備

直接通過引用 bootstrap 免費的 cdn 的方式進行,只需兩個文件:index.htmltest-array.js。內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="//cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
    <script src="./test-array.js"></script>
</head>
<body>
    
</body>
</html>
let r

// 封裝 console.log,使之更剪短
const l = (...ops) => {
    console.log(...ops)
}

{
    r = _.VERSION
    // => 4.17.21
    l(r)
}

{
    r = _.join(['a', 'b', 'c'], '~');
    // => 'a~b~c'
    l(r)
}

Tip: 所有測試都是如上結構

api 設計特性分析

  1. 有的方法可能是考慮兼容性,比如 _.fill,但 javascript 也有對應的原生方法(Array.prototype.fill),倘若使用 babel 庫幫忙轉換,那這類方法就有些雞肋
  2. 命名系列化。比如下文的 _.sortedIndex 系列,有 .sortedIndex、.sortedIndexOf、.sortedLastIndexOf、.sortedIndexBy、.sortedLastIndex、.sortedLastIndexBy 共6個,核心是 _.sortedIndex,通常系列方法有功能增強版,例如這裡的 _.sortedIndexBy,而命名中有 Last 通常從後往前查找
  3. 系列化的 api 通常有基礎版和加強版。例如 _.difference 系列,_.differenceBy_.differenceWith都是加強版
  4. 提供簡寫進一步提高程式碼簡潔性,比如下面的 _.isEqual
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
_.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
// => [{ 'x': 2, 'y': 1 }]

數組 api 總覽

僅列出非雞肋方法:
Tip: 筆者認為可以用原生方法非常便捷的替換的 api 就是雞肋。

  • _.chunk – 分塊。將數組(array)拆分成多個 size 長度的區塊,並將這些區塊組成一個新數組
  • _.compact – 壓緊。創建一個新數組,包含原數組中所有的非假值元素
  • _.difference 系列 – 。從第一個數組中排除給定數組中的值
  • _.drop 系列 – 減小。例如去除數組前面兩個元素
  • _.fromPairs/_.toPair – 一雙。例如 [['fred', 30], ['barney', 40]] <—> { 'fred': 30, 'barney': 40 }
  • _.intersection 系列 – 交集
  • _.pull – 移除數組中的值
  • _.sortedIndex – value 應插入已排序數組中的索引
  • _.sortedUniq – 唯一。對已排序的數組過濾重複值
  • _.take – 切片(從左提取 n 個元素)
  • _.union – 並集
  • _.uniq – 唯一(用於去重)
  • _.zip – 壓縮[1, 2], [10, 20], [100, 200] -> [[1, 10, 100], [2, 20, 200]]
  • _.unzip 系列 – 類似 _.zip。[[1, 2], [10, 20], [100, 200]] -> [[1, 10, 100], [2, 20, 200]]
  • _.without – 缺乏。可用 array.filter 替代。
  • _.xor 系列 – X集。只存在於某個數組中的值。

數組 api 詳細

_.chunk

_.chunk – 分塊。

// _.chunk(array, [size=1]) - 將數組(array)拆分成多個 size 長度的區塊,並將這些區塊組成一個新數組。 如果array 無法被分割成全部等長的區塊,那麼最後剩餘的元素將組成一個區塊。
{
    r = _.chunk(['a', 'b', 'c', 'd'], 2)
    // => [['a', 'b'], ['c', 'd']]
    l(r)

    r = _.chunk(['a', 'b', 'c', 'd'], 3)
    // => [['a', 'b', 'c'], ['d']]
    l(r)
}

_.compact

_.compact – 壓緊。可用 array.filter 實現

// _.compact(array) - 創建一個新數組,包含原數組中所有的非假值元素。例如false, null,0, "", undefined, 和 NaN 都是被認為是「假值」。
{
    // 返回過濾掉假值的新數組
    // 例如 false, null, 0, "", undefined, NaN 都是被認為是「假值」
    r = _.compact([false, null, 0, "", undefined, NaN, 1]);
    // => [1]
    l(r)

    // 可用 array.filter 實現
    r = [false, null, 0, "", undefined, NaN, 1].filter(v => !!(v))
    // => [1]
    l(r)
}

_.difference 系列

_.difference系列 – 差(從第一個數組中排除給定數組中的值)。_.differenceBy_.differenceWith都是加強版。

// _.difference(array, [values]) - 創建一個具有唯一array值的數組,每個值不包含在其他給定的數組中
// _.differenceBy(array, [values], [iteratee=_.identity]) - 這個方法類似_.difference ,除了它接受一個 iteratee (註:迭代器), 調用array 和 values 中的每個元素以產生比較的標準。
// _.differenceWith(array, [values], [comparator]) - 這個方法類似_.difference ,除了它接受一個 comparator (註:比較器),它調用比較array,values中的元素。 結果值是從第一數組中選擇
{

    // 從第一個數組中排除給定數組中的值。
    // 註:非數組會忽略
    r = _.difference([1, 2, 3, 4, 5, 6], [1, 2], [3], [4], 5, [6])
    // 5
    l(r)

    // 與 difference 類似。不同之處是每個值得調用 Math.floor 在比較,比如 2.2 和 2.5 認為是相等的
    r = _.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
    // => [3.1, 1.3]
    l(r)

    // The `_.property` iteratee shorthand.
    r = _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
    // => [{ 'x': 2 }]
    l(r)

    var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
    // 與 difference 類似。不同之處是每個值得調用 _.isEqual 這個比較器
    // 與 differenceBy 區別,感覺前者是迭代每個值並從中取得值進行比較,而 differenceWith 直接用比較器直接比較
    r = _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
    // => [{ 'x': 2, 'y': 1 }]
    l(r)
}

_.drop 系列

_.drop系列 – 減小(例如去除數組前面兩個元素)。某些場景可以使用 … 結構語法替換;_.dropRightWhile_.dropWhile 都是增強版。

// _.drop(array, [n=1]) - 創建一個切片數組,去除array前面的n個元素。(n默認值為1。)
// _.dropRight(array, [n=1]) - 創建一個切片數組,去除array尾部的n個元素。(n默認值為1。)
// _.dropRightWhile(array, [predicate=_.identity]) - 創建一個切片數組,去除array中從 predicate 返回假值開始到尾部的部分
// _.dropWhile(array, [predicate=_.identity]) - 創建一個切片數組,去除array中從起點開始到 predicate 返回假值結束部分
{
    // 去除前面兩個元素
    r = _.drop([1, 2, 3], 2);
    // => [3]
    l(r);

    // 用...解構語法替代上面例子
    [, , ...r] = [4, 5, 6]
    // => [6]
    l(r)

    // 去除後面兩個元素
    r = _.dropRight([1, 2, 3], 2);
    // => [1]
    l(r)

    // 作用難以理解。直接用 filter
    var users = [
        { 'user': 'barney', 'active': true },
        { 'user': 'fred', 'active': false },
        { 'user': 'pebbles', 'active': false }
    ];

    r = _.dropRightWhile(users, function (o) { return !o.active; });
    // => [{ 'user': 'barney', 'active': true }]
    l(r)
}

_.fromPairs & _.toPair

_.fromPairs & _.toPair – 一雙。前者可用 array.reduce 實現,後者可用 Object.entries 方便的替代。

// _.fromPairs(pairs) - 與_.toPairs正好相反;這個方法返回一個由鍵值對pairs構成的對象。
{
    let arr = [['fred', 30], ['barney', 40]]
    r = _.fromPairs(arr);
    // => { 'fred': 30, 'barney': 40 }
    l(r)

    // 用 reduce 重寫上述例子
    r = arr.reduce((obj, [key, value]) => {
        obj[key] = value
        return obj
    }, {})
    // => {fred: 30, barney: 40}
    l(r)

    r = _.toPairs(r)
    // => [['fred', 30], ['barney', 40]]
    l(r)

    // 用 Object.entries() 重寫上一個示例
    r = { fred: 30, barney: 40 }
    // Object.entries()方法返回一個給定對象自身可枚舉屬性的鍵值對數組
    r = Object.entries(r)
    // => [['fred', 30], ['barney', 40]]
    l(r)
}

_.intersection 系列

_.intersection – 交集。_.intersectionBy_.intersectionWith 是增強版。

// _.intersection([arrays]) - 數組的交集
// _.intersectionBy([arrays], [iteratee=_.identity]) - 這個方法類似_.intersection,區別是它接受一個 iteratee 調用每一個arrays的每個值以產生一個值,通過產生的值進行了比較
// _.intersectionWith([arrays], [comparator]) - 這個方法類似_.intersection,區別是它接受一個 comparator 調用比較arrays中的元素。結果值是從第一數組中選擇
{
    r = _.intersection([1, 2], [2, 3], [2, 3, 4]);
    // => [2]
    l(r)

    r = _.intersection([1, 2], [3, 4]);
    // => []
    l(r)

    r = _.intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor);
    // => [2.1]
    l(r)

    const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
    const others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];

    r = _.intersectionWith(objects, others, _.isEqual);
    // => [{ 'x': 1, 'y': 2 }]
    l(r)
}

_.pull 系列

_.pull – 移除數組中的值。_.pullAt 根據索引移除,_.pullAll 系列都是加強版。某些場景可使用 array.filter 替代。

// _.pull(array, [values]) - 移除數組array中所有和給定值相等的元素,使用SameValueZero 進行全等比較
// _.pullAll(array, values) - 這個方法類似_.pull,區別是這個方法接收一個要移除值的數組。
// _.pullAllBy(array, values, [iteratee=_.identity]) - 這個方法類似於_.pullAll ,區別是這個方法接受一個 iteratee(迭代函數) 調用 array 和 values的每個值以產生一個值,通過產生的值進行了比較。
// _.pullAllWith(array, values, [comparator]) - 這個方法類似於_.pullAll,區別是這個方法接受 comparator 調用array中的元素和values比較。
// _.pullAt(array, [indexes]) - 根據索引 indexes,移除array中對應的元素,並返回被移除元素的數組。Tip:刪除非連續的多個則不方便用 array.splice 替代
{
    r = [1, 2, 3, 1, 2, 3]
    _.pull(r, 2, 3);
    l(r)
    // => [1, 1]

    // 用 array.filter  重寫上一個示例
    r = [1, 2, 3, 1, 2, 3];
    r = r.filter(item => item !== 2 && item !== 3)
    // => [1, 1]
    l(r)

    // 數組中移除 { 'x': 3, 'y': 4 }
    r = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
    _.pullAllWith(r, [{ 'x': 3, 'y': 4 }], _.isEqual);
    // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
    l(r)

    // 移除索引 1 和 3。
    r = [5, 10, 15, 20];
    _.pullAt(r, 1, 3);
    // => [5, 15]
    l(r)
}

_.sortedIndex 系列

_.sortedIndex – value 應插入已排序數組中的索引。 _.sortedIndexBy 是增強版。_.sortedIndexOf[雞肋] 和 array.indexOf 類似。

:數組要已排序,否則得不到預期值。

// _.sortedIndex(array, value) - 使用二進位的方式檢索來決定 value值 應該插入到數組中 儘可能小的索引位置,以保證array的排序。
// _.sortedIndexOf(array, value) - 這個方法類似_.indexOf,除了它是在已經排序的數組array上執行二進位檢索。
// _.sortedLastIndexOf(array, value) - 這個方法類似_.lastIndexOf
// _.sortedIndexBy(array, value, [iteratee=_.identity]) - 這個方法類似_.sortedIndex
// _.sortedLastIndex(array, value) - 此方法類似於_.sortedIndex
// _.sortedLastIndexBy(array, value, [iteratee=_.identity]) - 這個方法類似_.sortedLastIndex
{
    // 數組有序,40 所放索引正確
    r = _.sortedIndex([20, 30, 50], 40)
    // => 2
    l(r)

    // 數組無序,筆者自己都不知道 40 應放哪裡
    r = _.sortedIndex([50, 20, 30], 40)
    // => 3
    l(r)

    r = [{ 'x': 4 }, { 'x': 5 }];
    r = _.sortedIndexBy(r, { 'x': 4.5 }, function (o) { return o.x; });
    // => 1
    l(r)

    // 和 array.indexOf 類似
    r = _.sortedIndexOf([4, 5, 5, 5, 6], 5);
    // => 1
    l(r)

    r = [4, 5, 5, 5, 6].indexOf(5)
    // => 1
    l(r)

    // _.sortedLastIndex(array, value) - 和 array.lastIndexOf() 類似
}

_.sortedUniq 系列

_.sortedUniq – 唯一。對已排序的數組過濾重複值,可用 Set 過濾。_.sortedUniqBy 是增強版

// _.sortedUniq(array) - 這個方法類似_.uniq,除了它會優化排序數組。
// _.sortedUniqBy(array, [iteratee]) - 這個方法類似_.uniqBy,除了它會優化排序數組。
{
    r = _.sortedUniq([1, 1, 2]);
    // => [1, 2]
    l(r)

    // 用 Set 過濾重複值
    r = [...new Set([1, 1, 2])]
    // => [1, 2]
    l(r)


    r = _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
    // => [1.1, 2.3]
    l(r)

    // 利用一個臨時數組實現上一個示例
    r = [1.1, 1.2, 2.3, 2.4]
    const tmp = []
    r = r.filter(item => {
        let v = Math.floor(item)
        if (tmp.includes(v)) {
            return false
        }
        tmp.push(v)
        return true
    })
    // => [1.1, 2.3]
    l(r)
}

_.take 系列

_.take – 切片(從左提取 n 個元素)。_.take 和 _.takeRight 可用 array.slice 替代。 _.takeWhile 是增強版。

// _.take(array, [n=1]) - 創建一個數組切片,從array數組的起始元素開始提取n個元素。
// _.takeRight(array, [n=1]) - 創建一個數組切片,從array數組的最後一個元素開始提取n個元素。
// _.takeWhile(array, [predicate=_.identity]) - 與 _.takeRightWhile 類似,只是方向不同
// _.takeRightWhile(array, [predicate=_.identity]) - 從array數組的最後一個元素開始提取元素,直到 predicate 返回假值
{
    r = _.take([1, 2, 3], 2);
    // => [1, 2]
    l(r)

    // 可用 array.slice 重寫上一個示例
    r = [1, 2, 3].slice(0, 2)
    // => [1, 2]
    l(r)

    r = _.takeRight([1, 2, 3, 4], 2);
    // => [3, 4]
    l(r)

    // 可用 array.slice 重寫上一個示例
    r = [1, 2, 3, 4].slice(-2)
    // => [3, 4]
    l(r)

    const users = [
        { 'user': 'barney', 'active': true },
        { 'user': 'fred', 'active': false },
        { 'user': 'pebbles', 'active': false }
    ];
    r = _.takeRightWhile(users, function (o) { return !o.active; });
    // => objects for ['fred', 'pebbles']
    l(r)

    // 自己實現 _.takeRightWhile
    r = []
    users.reverse().forEach(item => {
        if (item.active) {
            return false
        }
        r.push(item)
    })
    r.reverse()
    // => objects for ['fred', 'pebbles']
    l(r)
}

_.union 系列

_.union – 並集。_.union 可用 Set 方便實現。_.unionBy_.unionWith 是增強版。

// _.union([arrays]) - 創建一個按順序排列的唯一值的數組。所有給定數組的元素值使用SameValueZero做等值比較。
// _.unionBy([arrays], [iteratee=_.identity]) - 這個方法類似_.union ,除了它接受一個 iteratee (迭代函數),調用每一個數組(array)的每個元素以產生唯一性計算的標準
// _.unionWith([arrays], [comparator]) - 這個方法類似_.union, 除了它接受一個 comparator 調用比較arrays數組的每一個元素。例如比較對象
{
    r = _.union([1, 3, 5, 7, 3], [6, 4, 3]);
    // => [1, 3, 5, 7, 6, 4]
    l(r)

    // 兩個數組也可以用 Set 實現
    r = [...new Set([...[1, 3, 5, 7, 3], ...[6, 4, 3]])]
    // or r = Array.from(new Set([...[1, 3, 5, 7], ...[6, 4, 3]]))
    // => [1, 3, 5, 7, 6, 4]
    l(r)

    // 比較處理後的值
    r = _.unionBy([2.1], [1.2, 2.3], Math.floor)
    // => [2.1, 1.2]
    l(r)

    // 比較對象。對象的唯一性
    const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
    const others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];

    r = _.unionWith(objects, others, _.isEqual);
    // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
    l(r)
}

_.uniq 系列

_.uniq – 唯一(用於去重)。_.uniq 可用 Set 方便實現。_.uniqBy _.uniqWith 是增強版。

// _.uniq(array) - 創建一個去重後的array數組副本。
// _.uniqBy(array, [iteratee=_.identity]) - 這個方法類似_.uniq ,除了它接受一個 iteratee (迭代函數),調用每一個數組(array)的每個元素以產生唯一性計算的標準
// _.uniqWith(array, [comparator]) - 這個方法類似_.uniq, 除了它接受一個 comparator 調用比較arrays數組的每一個元素。例如比較對象
{
    r = _.uniq([2, 1, 2]);
    // => [2, 1]
    l(r)

    r = [...new Set([2, 1, 2])]
    // => [2, 1]
    l(r)

    // 比較處理後的值
    r = _.uniqBy([2.1, 1.2, 2.3], Math.floor);
    // => [2.1, 1.2]
    l(r)

    //  比較對象
    r = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];

    r = _.uniqWith(r, _.isEqual);
    // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
    l(r)
}

_.zip 系列

_.zip – 壓縮。_.zipWith_.zipObject_.zipObjectDeep都是增強版

// _.zip([arrays]) - 創建一個分組元素的數組,數組的第一個元素包含所有給定數組的第一個元素,數組的第二個元素包含所有給定數組的第二個元素,以此類推。
// _.zipWith([arrays], [iteratee=_.identity]) - 這個方法類似於_.zip,不同之處在於它接受一個 iteratee(迭代函數),來指定分組的值應該如何被組合。
// _.zipObject([props=[]], [values=[]]) - 這個方法類似_.fromPairs,除了它接受2個數組,第一個數組中的值作為屬性標識符(屬性名),第二個數組中的值作為相應的屬性值。
// _.zipObjectDeep([props=[]], [values=[]])- 這個方法類似_.zipObject,除了它支援屬性路徑。
{
    r = _.zip([1, 2], [10, 20], [100, 200])
    // => [[1, 10, 100], [2, 20, 200]]
    l(r)

    // 自己實現一個弱版本
    const zip = (...arrs) => {
        const result = []
        arrs[0].forEach((v, index) => {
            const tmp = []
            arrs.forEach(item => tmp.push(item[index]))
            result.push(tmp)
        })
        return result
    }

    r = zip([1, 2], [10, 20], [100, 200])
    // => [[1, 10, 100], [2, 20, 200]]
    l(r)

    r = _.zipWith([1, 2], [10, 20], [100, 200], function (a, b, c) {
        return a + b + c;
    });
    // => [111, 222]
    l(r)

    // 組合成對象
    r = _.zipObject(['a', 'b'], [1, 2]);
    // => { 'a': 1, 'b': 2 }
    l(r)

    r = _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2])
    // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
    l(r)
}

_.unzip 系列

_.unzip – 解壓。似於_.zip。_.unzipWith 是增強版。

// _.unzip(array) - 這個方法類似於_.zip,除了它接收分組元素的數組,並且創建一個數組,分組元素到打包前的結構。(:返回數組的第一個元素包含所有的輸入數組的第一元素,第一個元素包含了所有的輸入數組的第二元素,依此類推。)
// _.unzipWith(array, [iteratee=_.identity]) - 此方法類似於_.unzip,除了它接受一個iteratee指定重組值應該如何被組合。增強版
{
    r = _.unzip([1, 2], [10, 20], [100, 200])
    // => []
    l(r)
    // 用數組包裹後,就和 _.zip 效果相同
    r = _.unzip([[1, 2], [10, 20], [100, 200]])
    // => [[1, 10, 100], [2, 20, 200]]
    l(r)

    r = _.unzipWith([[1, 10, 100], [2, 20, 200]], _.add);
    // => [3, 30, 300]
    l(r)
}

_.without

_.without – 缺乏。可用 array.filter 替代

// _.without(array, [values]) - 創建一個剔除所有給定值的新數組。
{
    r = _.without([2, 1, 2, 3], 1, 2);
    // => [3]
    l(r)

    r = [2, 1, 2, 3].filter(item => ![1, 2].includes(item))
    // => [3]
    l(r)
}

_.xor 系列

_.xor – X集(只存在於某個數組中的值)。_.xorBy_.xorWith 是增強版

// _.xor([arrays]) - 創建一個給定數組唯一值的數組,使用symmetric difference做等值比較。返回值的順序取決於他們數組的出現順序。每個元素的差集,即只存在於某個數組中的值,其他數組沒有改值。
// _.xorBy([arrays], [iteratee=_.identity]) - 這個方法類似_.xor ,除了它接受 iteratee(迭代器),這個迭代器 調用每一個 arrays(數組)的每一個值,以生成比較的新值。增強版
// _.xorWith([arrays], [comparator]) - 該方法是像_.xor,除了它接受一個 comparator ,以調用比較數組的元素。增強版
{
    r = _.xor([1, 2], [3, 2], [4, 2], [5])
    // => [1, 3, 4, 5]
    l(r)
    r = _.xor([1, 2], [3, 2], [4, 2, 5], [5])
    // => [1, 3, 4]
    l(r)

    // 轉換後的值比較
    r = _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
    // => [1.2, 3.4]
    l(r)

    // 對象比較
    const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
    const others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
    r = _.xorWith(objects, others, _.isEqual);
    // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
    l(r)
}

雞肋

_.concat

_.concat – 連接數組。與 array.concat 效果相同,也可用 es6+ 語法 ... 實現

// _.concat(array, [values]) - 創建一個新數組,將array與任何數組 或 值連接在一起。
// 
{
    const array = [1];
    r = _.concat(array, 2, [3], [[4]]);

    console.log(r);
    // => [1, 2, 3, [4]]

    // 與原生數組的 concat 效果相同
    r = array.concat(2, [3], [[4]])
    // => [1, 2, 3, [4]]
    l(r)

    r = [...array, 2, ...[3], ...[[4]]]
    // [1, 2, 3, [4]]
    l(r)
}
_.fill

_.fill – 填充。可用 array.fill 替代

// _.fill(array, value, [start=0], [end=array.length]) - 使用 value 值來填充(替換) array,從start位置開始, 到end位置結束(但不包含end位置)。
{

    let array = [1, 2, 3];
    r = [...array]
    _.fill(r, 'a');
    l(r)
    // => ['a', 'a', 'a']

    // array.fill 重寫上一個示例
    // fill() 方法用一個固定值填充一個數組中從起始索引到終止索引內的全部元素。不包括終止索引。
    r = [...array]
    r.fill('b')
    l(r)
    // =>  ['b', 'b', 'b']

    r = [4, 6, 8, 10]
    _.fill(r, '*', 1, 3)
    l(r)
    // => [4, '*', '*', 10]

    // array.fill 重寫上一個示例
    r = [4, 6, 8, 10]
    r.fill('*', 1, 3)
    l(r)
    // => [4, '*', '*', 10]
}

_.findIndex

_.findIndex – 可用 Array.prototype.findIndex 替代

// _.findIndex(array, [predicate=_.identity], [fromIndex=0]) - 該方法類似_.find,區別是該方法返回第一個通過 predicate 判斷為真值的元素的索引值(index),而不是元素本身。
// _.findLastIndex(array, [predicate=_.identity], [fromIndex=array.length-1])
{
    let users = [
        { 'user': 'fred', 'active': false },
        { 'user': 'fred', 'active': true },
        { 'user': 'pebbles', 'active': true }
    ];

    r = _.findIndex(users, function (o) { return o.user == 'fred' && o.active === false });
    // => 0
    l(r)

    // array.findIndex 重寫上一個示例
    // findIndex()方法返回數組中滿足提供的測試函數的第一個元素的索引。若沒有找到對應元素則返回 -1。
    r = users.findIndex(o => o.user == 'fred' && o.active === false)
    // => 0
    l(r)

    // The `_.matches` iteratee shorthand.
    r = _.findIndex(users, { 'user': 'fred', 'active': true });
    // => 1
    l(r)
}
_.head

_.head – 可用 arr[index] 或 att.at(index) 替代

// _.head(array) - 獲取數組 array 的第一個元素。可用 arr[index] 或 att.at(index) 替代。
{
    const arr = [2, 3, 4]
    r = _.head(arr)
    // => 2
    l(r)

    // 需要 chrome 92+
    // r = arr.at(0)
    // => 2
    // l(r)
}
_.flatten

_.flatten – 變平。array.flat 能非常方便的替代這3個api。

// _.flatten(array) - 減少一級array嵌套深度。
// _.flattenDeep(array) - 將array遞歸為一維數組。
// _.flattenDepth(array, [depth=1]) - 根據 depth 遞歸減少 array 的嵌套層級
{
    let arr = [1, [2, [3, [4]], 5]]
    r = _.flatten(arr);
    // => [1, 2, [3, [4]], 5]
    l(r)

    // array.flat 重寫上一個示例
    r = arr.flat()
    // => [1, 2, [3, [4]], 5]
    l(r)

    
    r = _.flattenDeep(arr)
    // => [1, 2, 3, 4, 5]
    l(r)

    // 用 array.flat 重寫上一個示例
    r = arr.flat(Infinity)
    // => [1, 2, 3, 4, 5]
    l(r)
}
_.remove

_.remove – 刪除。可用 array.filter 替代。

// _.remove(array, [predicate=_.identity]) - 移除數組中predicate(斷言)返回為真值的所有元素,並返回移除元素組成的數組
{
    let array = [1, 2, 3, 4];
    r = _.remove(array, function (n) {
        return n % 2 == 0;
    });

    // => [2, 4]
    l(r)

    // 用 array.filter 替代
    r = [1, 2, 3, 4]
    r = r.filter(item => item % 2 === 0)
    // => [2, 4]
    l(r)
}
_.tail

_.tail – 尾部。可用 array.slice 替代

// _.tail(array) - 獲取除了array數組第一個元素以外的全部元素。
{
    r = _.tail([1, 2, 3]);
    // => [2, 3]
    l(r)

    r = [1, 2, 3].slice(1)
    // => [2, 3]
    l(r)
}
其他
  • _.initial(array) – 獲取數組array中除了最後一個元素之外的所有元素。名字不好記。可用 [1, 2, 3].slice(0, -1) 替代 或 let [, ...r] = [1,2,3].reverse(); r.reverse()

  • _.join(array, [separator=’,’]) – 可用 Array.prototype.join 替代

  • _.last(array) – 獲取array中的最後一個元素。 可用 array[array.length - 1] 替代

  • _.lastIndexOf(array, value, [fromIndex=array.length-1]) – 可用 Array.prototype.lastIndexOf 替代

  • _.nth(array, [n=0]) – 獲取array數組的第n個元素。直接用數組索引獲取 或 Array.prototype.at 替代

  • _.reverse(array) – 逆序。可用 array.reverse 替代。

  • _.slice(array, [start=0], [end=array.length]) – slice。可用 array.slice 替代

  • _.indexOf – 可用 Array.prototype.indexOf 替代

Tags: