摘要:到這里,源碼分析完了。但是,有兩個致命的特性的遍歷不能保證順序會遍歷所有可枚舉屬性,包括繼承的屬性。的遍歷順序依賴于執行環境,不同執行環境的實現方式可能會不一樣。
小時候,鄉愁是一枚小小的郵票,
我在這頭,
母親在那頭。
長大后,鄉愁是一張窄窄的船票,
我在這頭,
新娘在那頭。
后來啊,
鄉愁是一方矮矮的墳墓,
我在外頭,
母親在里頭。
而現在,
鄉愁是一灣淺淺的海峽,
我在這頭,
大陸在那頭。
——余光中《鄉愁》
本文為讀 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 = 0 const 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 會遍歷所有可枚舉屬性,包括繼承的屬性。
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 = 0 const _self = this return { 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 = 0 while (index < this.length) { yield this[index++] * 2 } }
因此在不改寫 Symbol.iterator 的情況下,使用 for...of 來遍歷數組是安全的,因為這個方法是數組的原生方法。
關于 Iterator 和 Generator 可以點擊參考中的鏈接詳細查看。
參考MDN:迭代器和生成器
Iterator 和 for...of 循環
Generator 函數的語法
Lodash源碼講解(3)-compact函數
MDN:for...of
MDN:for…in
License署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
最后,所有文章都會同步發送到微信公眾號上,歡迎關注,歡迎提意見:
作者:對角另一面
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92209.html
摘要:首先我們先說一下這個函數的作用,這個函數接收一個數組作為參數然后將數組中所有通過布爾轉換可以變為的值去除從而生成一個新的數組。 原文首發于Lodash源碼講解 這是我們閱讀Lodash源碼的第3篇博客,在這篇文章里我們來學習一下Lodash的compact方法。 compact函數內部沒有依賴別的函數,讓我們先來看一下compact函數的源碼。 /** * Creates an ar...
摘要:從表中可以看到,比較運算符的優先級為,而三元表達式條件運算符的優化級為,因此可以確定比較運算符的優先級要比三元表達式的要高,循環條件其實等價于第二種寫法。從上表中也可以看出前綴自增比比較運算符的優化級要高。 我悟出權力本來就是不講理的——蟑螂就是海米;也悟出要造反,內心必須強大到足以承受任何后果才行。——北島《城門開》 本文為讀 lodash 源碼的第十篇,后續文章會更新到這個倉庫中...
摘要:文檔地址中文文檔英文文檔源碼地址創建一個新數組,包含原數組中所有的非假值元素。例如和都是被認為是假值。下面對比一下兩者效率,如下圖傳送門可以看到使用更快,如果沒有兼容性需求,還是使用原生函數比較好。 百忙之中(閑來無事)想抽點時間好好讀一下源碼,于是就選了Lodash來寫一個系列罷。讀源碼順序就按照loadsh文檔順序來。 文檔地址:中文文檔?? 英文文檔源碼地址:gayhub ...
摘要:作用與用法是的內部函數,之前在源碼分析之緩存介紹過一種這樣的數據結構這是一個二維數組,每項中的第一項作為緩存對象的,第二項為緩存的值。 這個世界需要一個特定的惡人,可以供人們指名道姓,千夫所指:全都怪你。——村上春樹《當我談跑步時我談些什么》 本文為讀 lodash 源碼的第六篇,后續文章會更新到這個倉庫中,歡迎 star:pocket-lodash gitbook也會同步倉庫的更新...
摘要:依賴源碼分析之緩存使用方式的進一步封裝源碼分析之源碼分析之源碼分析之的實現源碼分析之源碼分析的調用如果有傳遞,則先調用,使用生成要比較數組的映射數組。循環完畢,沒有在第二個數組中發現相同的項時,將該項存入數組中。 外部世界那些破舊與貧困的樣子,可以使我內心世界得到平衡。——卡爾維諾《煙云》 本文為讀 lodash 源碼的第十七篇,后續文章會更新到這個倉庫中,歡迎 star:pocke...
閱讀 1775·2021-09-22 15:10
閱讀 1272·2021-09-07 09:58
閱讀 2340·2019-08-30 15:44
閱讀 1644·2019-08-26 18:29
閱讀 2039·2019-08-26 13:35
閱讀 766·2019-08-26 13:31
閱讀 726·2019-08-26 11:42
閱讀 1071·2019-08-23 18:39