lodash源码分析之compact中的遍历
小時候,
鄉愁是一枚小小的郵票,
我在這頭,
母親在那頭。
長大后,鄉愁是一張窄窄的船票,
我在這頭,
新娘在那頭。
后來啊,
鄉愁是一方矮矮的墳墓,
我在外頭,
母親在里頭。
而現在,
鄉愁是一灣淺淺的海峽,
我在這頭,
大陸在那頭。
——余光中《鄉愁》
本文為讀 lodash 源碼的第三篇,后續文章會更新到這個倉庫中,歡迎 star:pocket-lodash
gitbook也會同步倉庫的更新,gitbook地址:pocket-lodash
作用與用法
compact 函數用來去除數組中的假值,并返回由不為假值元素組成的新數組。
false、null、0、 ""、undefined 和 NaN 都為假值。
例如:
var arr = [1,false,2,null,3,0,4,NaN,5,undefined] _.compact(arr) // 返回 [1,2,3,4,5]源碼
function compact(array) {let resIndex = 0const result = []if (array == null) {return result}for (const value of array) {if (value) {result[resIndex++] = value}}return result }compact 的源碼只有寥寥幾行,相當簡單。
首先判斷傳入的數組是否為 null 或者 undefined,如果是,則返回空數組。
然后用 for...of 來取得數組中每項的值,如果不為假值,則存入新數組 result 中,最后將新數組返回。
到這里,源碼分析完了。
但是在看源碼的時候,發現這里用了 for...of 來做遍歷,其實除了 for...of 外,也可以用 for 或者 for...in 來做遍歷,那為什么最后選了 for...of 呢?
數組中的for循環
使用 for 循環,很容易就將 compact 中關于循環部分的源碼改寫成以下形式:
for (let i = 0; i < array.length; i++) {const value = array[i]if (value) {result[resIndex++] = value}}這樣寫,肯定是沒有問題的,但是不夠簡潔。
for…in
再來看 for...in 循環,先來將源碼改寫一下:
for (let index in array) {const value = array[i]if (value) {result[resIndex++] = value} }先看看MDN上關于 for...in 的用法:
for...in語句以任意順序遍歷一個對象的可枚舉屬性。
關于可枚舉屬性,可以點擊上面的鏈接到MDN上了解一下,這里不做太多的解釋。
在數組中,數組的索引是可枚舉屬性,可以用 for...in 來遍歷數組的索引,數組中的稀疏部分不存在索引,可以避免用 for 循環造成無效遍歷的弊端。
但是,for...in 有兩個致命的特性:
for...in 的遍歷順序依賴于執行環境,不同執行環境的實現方式可能會不一樣。單憑這一點,就斷然不能在數組遍歷中使用 for...in,大多數情況下,順序對于數組的遍歷都相當重要。
關于第二點,先看個例子:
var arr = [1,2,3] arr.foo = 'foo' for (let index in arr) {console.log(index) }在這個例子中,你期望輸出的是 0,1,2,但是最后輸出的可能是 0,1,2,foo (for...in 不能保證順序)。因為 foo 也是可枚舉屬性,在 for..in 會被遍歷出來。
for…of
最后來看看 for...of。
當我們在控制臺中打印一個數組,并將它展開來查看時,會在數組的原型鏈上發現一個很特別的屬性 Symbol.iterator。
其實 for...of 循環內部調用的就是數組原型鏈上的 Symbol.iterator 方法。
Symbol.iterator 在調用的時候會返回一個遍歷器對象,這個遍歷器對象中包含 next 方法,for...of 在每次循環的時候都會調用 next 方法來獲取值,直到 next 返回的對象中的 done屬性值為 true 時停止。
其實我們也可以手動調用來模擬遍歷的過程:
const arr = [1,2,3] const iterator = a[Symbol.iterator]() iterator.next() // {value: 1, done: false} iterator.next() // {value: 2, done: false} iterator.next() // {value: 3, done: false} iterator.next() // {value: undefined, done: true}知道這些原理后,完全可以改寫數組中的 Symbol.iterator 方法,例如遍歷時將數組中的值都乘2:
Array.prototype[Symbol.iterator] = function () {let index = 0const _self = thisreturn {next: function () {if (index < _self.length) {return {value: _self[index++] * 2, done: false}} else {return {done: true}}}} }使用 Generator 函數可以寫成以下的形式:
Array.prototype[Symbol.iterator] = function* () {let index = 0while (index < this.length) {yield this[index++] * 2 } }因此在不改寫 Symbol.iterator 的情況下,使用 for...of 來遍歷數組是安全的,因為這個方法是數組的原生方法。
關于 Iterator 和 Generator 可以點擊參考中的鏈接詳細查看。
參考
License
署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
最后,所有文章都會同步發送到微信公眾號上,歡迎關注,歡迎提意見:
作者:對角另一面
轉載于:https://www.cnblogs.com/hefty/p/8055931.html
總結
以上是生活随笔為你收集整理的lodash源码分析之compact中的遍历的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用卡被止付还要还款吗?逾期后果你承受的
- 下一篇: 民生银行中午休息吗?节假日休息吗?