使用技巧_Lodash 使用技巧
點(diǎn)擊 閱讀原文 可使用 語(yǔ)雀 查看,排版樣式更佳。
我第一次使用 Lodash 還是在實(shí)習(xí)的時(shí)候,當(dāng)時(shí)并不喜歡用它,因?yàn)槲矣X(jué)得:上面很多東西在 ES6+ 已經(jīng)實(shí)現(xiàn)了,還有就是很多函數(shù)看不懂怎么使用。
直到有一次,我在 npm 上看到, Lodash 的周下載量是 React 的四倍多,就覺(jué)得應(yīng)該好好了解下這個(gè)庫(kù)了。
使用原因
比 ES6+ 更強(qiáng)大
比如 _.drop,它就相當(dāng)于 Array.prototype.shift(),但 _.drop 可以增加參數(shù),扔掉 n 個(gè),而 shift 只能扔掉 1 個(gè)。再比如 _.set _.get 這在操作深層數(shù)據(jù)結(jié)構(gòu)時(shí)非常有用,而 js 本身并未提供這種函數(shù)。
不會(huì)輕易報(bào)錯(cuò)
以 _.includes 為例:
就是參數(shù)是 undefined,代碼也能正常執(zhí)行下去,但你如果使用 Array.prototype.includes() 那就會(huì)變成 undefined.includes(),這不就報(bào)錯(cuò)了嘛。
0 dependencies
沒(méi)有外部依賴,代碼全是由官方人員維護(hù),有足夠的安全性、穩(wěn)定性,如果你了解 node_modules 的痛點(diǎn),就應(yīng)該知道這是多么的重要。
理想情況下,沒(méi)人使用 ES6+ 的一些 prototype 上的操作,而是全部使用 Lodash 來(lái)實(shí)現(xiàn),那就能干掉 polyfill 了,減少代碼打包的體積(但有可能你引用的三方包需要 polyfill,你的努力就全白費(fèi)了 ?)。
使用技巧
其實(shí)只要仔細(xì)看下官方文檔就可以使用了(沒(méi)有什么是看官方文檔解決不了的,如果有,那就再看一遍 ?)。當(dāng)然,官方文檔也確實(shí)有些枯燥,下面介紹下我常使用的方法以及用途吧。
文檔把函數(shù)一共分了幾大類,最常用的莫過(guò)于 Array 和 Collection 了(Collection 就是 Array 或 Object)。
Array
_.chunk(array, [size=1])
這個(gè)就是把一個(gè)數(shù)組按照 size 去分成好幾個(gè)數(shù)組,我一直覺(jué)得這個(gè)沒(méi)啥用,直到我遇到了這種需求:
就是寫(xiě)一個(gè)小面板,那里 3 個(gè)一列,順序放置,這不就是 chunk 嘛,真香!
_.compact(array)
把 array 中的 falsey 值去掉,可用于給后端傳參時(shí)_.difference(array, [values])
去掉 array 中和 values 相同的值。返回新數(shù)組,不會(huì)更改 array
_.differenceBy(array, [values], [iteratee=_.identity])
這里的 _.xxxBy 對(duì)后面有指導(dǎo)性意義。重點(diǎn)看 iteratee 參數(shù),它有個(gè)默認(rèn)值是 _.identity(它是一個(gè)函數(shù),它返回接收到的第一個(gè)參數(shù)),iteratee 應(yīng)該是一個(gè)函數(shù),它只帶一個(gè)參數(shù) value(array 和 values 的值),iteratee 的作用就是你可以接收 value 返回 nextValue,nextValue 用于 _.difference,就是相當(dāng)于你有的進(jìn)一步去改造 array 和 values 的能力,但比較還是由 _.differenceBy 來(lái)完成。當(dāng) iteratee 字符串或其他一些特殊類型的字面量時(shí),可以代表某些函數(shù)簡(jiǎn)寫(xiě)的參數(shù),如下:
這里 iteratee 是字符串 'x',其實(shí)就相當(dāng)于如下代碼:
有挺多函數(shù)都可以使用這種簡(jiǎn)寫(xiě)操作,具體的可以參考下文檔。
_.differenceWith(array, [values], [comparator])
這里的 _.xxxWith 對(duì)后面有指導(dǎo)性意義。這里 comparator 函數(shù)就更強(qiáng)大了,比較的工作也由你來(lái)完成,你只需要在 comparator 函數(shù)中返回布爾值就好了,comparator 的參數(shù)是 (arrVal, othVal)
_.drop(array, [n=1])
在 array 中扔掉前 n 個(gè)元素,返回其余后面的元素,.dropRight 是倒著扔。.dropWhile(array, [predicate=.identity]) 是一直扔,直到 predicate 返回 false 為止,.dropRightWhile 同理
_.take(array, [n=1])在 array 只拿前 n 個(gè)元素,其余的不要,_.takeRight _.takeWhile _.takeRightWhile 同理
.findIndex(array, [predicate=.identity], [fromIndex=0])
遍歷 array,找到第一個(gè) predicate 函數(shù)返回 true 的值的下標(biāo)并返回,_.findLastIndex 是倒著找,這個(gè)和 Collection 中的 _.find 非常像,只不過(guò) _.find 返回的是找到值,而不是下標(biāo)(并且 Object 也沒(méi)下標(biāo)呀),_.findLast 同理_.head(array)
返回 array 中第一個(gè)元素_.last(array)
返回 array 中最后一個(gè)元素_.tail(array)
返回一個(gè)數(shù)組,除了 array 中第一個(gè)元素_.initial(array)
返回一個(gè)數(shù)組,除了 array 中最后一個(gè)元素
_.flatten(array)
拍平 array 中的數(shù)組的第一層,可用于兼容參數(shù),比如 foo(a) 參數(shù) a 可以是一個(gè)字符串或字符串?dāng)?shù)組,那 foo 函數(shù)里,就可以調(diào)用 _.flatten([a]) 就能統(tǒng)一拿到 a 數(shù)組。_.flattenDeep 是所有層都拍平,_.flattenDepth 可以指定層。_.intersection([arrays])
返回 arrays(代表多個(gè)數(shù)組)中的交集,_.intersectionBy 與 _.intersectionWith 同理
//?[2,?1]
_.union([arrays])
返回 arrays(代表多個(gè)數(shù)組)中的并集, _.unionBy 與 _.unionWith 同理
//?[2,?4,?6,?1,?3,?9]
_.nth(array, [n=0])
返回 array 中的第 n 項(xiàng),有趣的是,n 可以是負(fù)數(shù),代表倒數(shù),與 Array.prototype.slice() 類似
_.pullAll(array, values)
拿掉 array 中和 values 相同的值。和上面的 _.difference 作用一樣,只不過(guò)會(huì)直接改變 array 原數(shù)組,_.pullAllBy 和 _.pullAllWith 同理_.pullAt(array, [indexes])
拿掉 array 中 indexes 下標(biāo)的值,會(huì)改變 array 原數(shù)組
_.remove(array, [predicate=_.identity])
通過(guò) predicate 函數(shù),移走 array 中返回 false 的元素,會(huì)改變 array 原數(shù)組_.uniq(array)
給 array 去重,_.uniqBy 與 _.uniqWith 同理,數(shù)組去重還是很常用噠(下次面試官說(shuō):數(shù)組去個(gè)重,你就可以寫(xiě) _.uniq([1, 1, 2]) 試試,不知道面試官會(huì)不會(huì)打你 ?)
Collection
不知你有沒(méi)有想過(guò),為什么 Collection 是 Array 或 Object 呢?還有為什么 JS 的數(shù)組不會(huì)越界呢?
其實(shí) JS 中的數(shù)組并不是真正意義上的數(shù)組,如我搜的 C++ 數(shù)組定義如下:
C++ 支持?jǐn)?shù)組數(shù)據(jù)結(jié)構(gòu),它可以存儲(chǔ)一個(gè)固定大小的相同類型元素的順序集合。所有的數(shù)組都是由連續(xù)的內(nèi)存位置組成。最低的地址對(duì)應(yīng)第一個(gè)元素,最高的地址對(duì)應(yīng)最后一個(gè)元素。
這時(shí)你應(yīng)該想起來(lái)了,JS 中的函數(shù)、數(shù)組、正則表達(dá)式的原型鏈上都有 Object:(每一個(gè)對(duì)象都有 __proto__ 屬性,當(dāng)調(diào)用這個(gè)對(duì)象的變量或方法時(shí),如果沒(méi)有找到,會(huì)沿著 __proto__ 屬性一直向上找)
所以 JS 數(shù)組只是一種自帶一些特殊操作(如 push、shift)的 Object,所以類數(shù)組就是一個(gè)帶有 length 屬性的對(duì)象,用 Array.from() 就能輕松的把它轉(zhuǎn)換為數(shù)組。
這也是為什么 JS 用數(shù)組實(shí)現(xiàn)一個(gè) 棧或隊(duì)列 都非常簡(jiǎn)單(當(dāng)然,我這里說(shuō)的只是簡(jiǎn)單的模擬行為),而 C++ 這種,就還需要特殊的數(shù)據(jù)結(jié)構(gòu)(queue、stack)來(lái)支持。我也認(rèn)為,這正是 JS 的精妙之處,因?yàn)檫m用場(chǎng)景就是如此。
回到正題,接下來(lái)是 Collection 的常用方法。
_.countBy(collection, [iteratee=_.identity])
通過(guò) iteratee 函數(shù)的返回值去給 collection 分類計(jì)數(shù),返回值為 key 計(jì)數(shù)值為 value_.groupBy(collection, [iteratee=_.identity])
通過(guò) iteratee 函數(shù)的返回值去給 collection 分類,返回值為 key 被分類的項(xiàng)為 value
_.forEach(collection, [iteratee=_.identity])
遍歷 collection,iteratee 可以返回 false,循環(huán)就會(huì) break。這一個(gè)方法就完成了 Array.prototype.forEach() 和 Object.entries(),賊強(qiáng)(注意:collection 如果是 Object 且有 length 屬性,就會(huì)被當(dāng)做數(shù)組來(lái)處理,想要被正確處理的話,可以使用 _.forIn 或 .forOwn,還是建議正常 Object 就不要用 length 屬性了吧).forEachRight 同理_.every _.some _.includes _.find _.findLast _.filter _.map _.reduce _.reduceRight
以上都是 JS 原生存在的方法了,那為什么不用原生的而要用這里的呢?
瀏覽器兼容性更好;這些既能用到 Array 上又能用到 Object 上,有時(shí)還能用到 String 上;實(shí)現(xiàn)更強(qiáng)的功能,代碼更少,如下舉例:
//?Lodash?解法
//?The?`_.property`?iteratee?shorthand.
_.map(users,?'user');
//?=>?['barney',?'fred']
//?原生解法
users.map(i?=>?i.user);
//?=>?['barney',?'fred']
_.sortBy(collection, [iteratees=[_.identity]])
給 collection 排序,這是個(gè)比較正常的排序,默認(rèn)升序,并不像 Array.prototype.sort() 都要轉(zhuǎn)成字符串再排序,而且很容易就能支持相等時(shí)的二級(jí)排序。
array1.sort();
//?=>?[1,?100000,?21,?30,?4]
_.sortBy(array1);
//?=>?[1,?4,?21,?30,?100000]?
var?users?=?[
??{?user:?'fred',?age:?48?},
??{?user:?'barney',?age:?36?},
??{?user:?'fred',?age:?40?},
??{?user:?'barney',?age:?34?},
];
//?當(dāng)?user?相等時(shí),使用?age?排序
_.sortBy(users,?['user',?'age']);
//?=>?objects?for?[['barney',?34],?['barney',?36],?['fred',?40],?['fred',?48]]
_.orderBy(collection, [iteratees=[_.identity]], [orders])
這個(gè)和 _.sortBy 一樣的,就是可以自定義升序或降序
_.partition(collection, [predicate=_.identity])
把 collection 分為兩份,分別是 predicate 返回真的和假的
_.reject(collection, [predicate=_.identity])
和 _.filter 相反,返回 predicate 為假的值
_.sample(collection)
返回 collection 中任意一個(gè)值,_.sampleSize 返回 collection 中任意 n 個(gè)值,不會(huì)重復(fù)
_.shuffle(collection)
返回打亂順序后的 collection_.size(collection)
返回 collection 的項(xiàng)目個(gè)數(shù),感覺(jué)比 length 好用多了
其他類型
有些其他類型的,也比較常用,在此說(shuō)下:_.now()
返回時(shí)間戳_.debounce(func, [wait=0], [options={}])
返回 func 經(jīng)過(guò)防抖后的函數(shù)_.throttle(func, [wait=0], [options={}])
返回 func 經(jīng)過(guò)節(jié)流后的函數(shù)
這兩個(gè)函數(shù)常用于輸入框搜索中,如在 React Hooks 下,可以這樣使用:
const?handleRequest?=?useRef(
??debounce(url?=>?{
????request(url);
??},?600),
);
_.unary(func)
讓 func 只會(huì)使用第一個(gè)參數(shù)
_.cloneDeep(value)
深克隆 value_.isEqual(value, other)
深比較 value 和 other 是否相等。這塊讓我想到一個(gè)有趣的問(wèn)題,記得有人說(shuō)深比較是否相等可以用 JSON.stringify() 其實(shí)這個(gè)不對(duì),如下所示就能證明:
注意:這兩個(gè)要慎用啊,因?yàn)槎紩?huì)一直遞歸到最深層,建議只有當(dāng)你知道這個(gè)對(duì)象很簡(jiǎn)單,并且以后也不會(huì)變復(fù)雜的情況下,再使用他們。
_.get(object, path, [defaultValue])
獲取 object 的 path 上的值,如果沒(méi)有,就用 defaultValue,這個(gè)我經(jīng)常使用,當(dāng)不確定這個(gè)值是否存在時(shí),還能給個(gè) defaultValue 來(lái)繼續(xù)下面的操作_.set(object, path, value)
給 object 的 path 賦值 value,如果 path 的值不存在,則會(huì)一直創(chuàng)建_.unset(object, path)
相等于 delete 掉 path 上的值
_.omit(object, [paths])
忽略掉 object 的 paths 上的值_.pick(object, [paths])
只取 object 的 paths 上的值_.matches(source)
返回一個(gè)函數(shù),如果部分匹配正確,那這個(gè)函數(shù)將返回 true_.range([start=0], end, [step=1])
生成一個(gè)范圍內(nèi)的數(shù)字?jǐn)?shù)組
結(jié)語(yǔ)
本文只介紹了一些簡(jiǎn)單、常用的函數(shù),希望能以通俗易懂的方式表達(dá)出來(lái)。提前把這些方法的作用看一下還是有必要的,當(dāng)遇到合適場(chǎng)景的時(shí)候,就直接使用,而不是自己造(造出的又全是 bug?)。
歡迎關(guān)注我的公眾號(hào),或使用語(yǔ)雀 https://www.yuque.com/zcue/blog 查看:
總結(jié)
以上是生活随笔為你收集整理的使用技巧_Lodash 使用技巧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 锂电池放空后充不进电_锂电池过度放电后充
- 下一篇: access 江苏计算机二级_你与计算机