在那小小的夢的暖閣,我爲你收藏起整個季節的煙雨。javascript
——洛夫《靈河》java
本文爲讀 lodash 源碼的第四篇,後續文章會更新到這個倉庫中,歡迎 star:pocket-lodashgit
gitbook也會同步倉庫的更新,gitbook地址:pocket-lodashes6
Hash
顧名思義,就是要有一個離散的序列,根據 key
來儲取數據。而在 javascript 中,最適合的無疑是對象了。github
Hash
在 lodash 的 .internal
文件夾中,做爲內部文件來使用。lodash 會根據不一樣的數據類型選擇不一樣的緩存方式,Hash
即是其中的一種方式,這種方式只能緩存 key
的類型符合對象鍵要求的數據。數組
Hash
只接收一個二維數組做爲參數,調用方式以下:緩存
new Hash([['tes1', 1],['test2',2],['test3',3]])
複製代碼
其中子項中的第一項會做爲 key
,第二項是須要緩存的值。微信
Hash
實例化的結果以下:數據結構
{
size: 3,
__data__: {
test1: 1,
test2: 2,
test3: 3
}
}
複製代碼
緩存的數量儲存在 __data__
的對象中。ui
後面將會講到,除了使用 Hash
方式緩存數據外,還會用到 Map
,lodash 在設計 Hash
的數據管理接口時,也與 Map
的接口一致,可是不會包含 Map
的遍歷方法。
先來看看這些接口都有那些:
const HASH_UNDEFINED = '__lodash_hash_undefined__'
class Hash {
constructor(entries) {
let index = -1
const length = entries == null ? 0 : entries.length
this.clear()
while (++index < length) {
const entry = entries[index]
this.set(entry[0], entry[1])
}
}
clear() {
this.__data__ = Object.create(null)
this.size = 0
}
delete(key) {
const result = this.has(key) && delete this.__data__[key]
this.size -= result ? 1 : 0
return result
}
get(key) {
const data = this.__data__
const result = data[key]
return result === HASH_UNDEFINED ? undefined : result
}
has(key) {
const data = this.__data__
return data[key] !== undefined
}
set(key, value) {
const data = this.__data__
this.size += this.has(key) ? 0 : 1
data[key] = value === undefined ? HASH_UNDEFINED : value
return this
}
}
export default Hash
複製代碼
constructor(entries) {
let index = -1
const length = entries == null ? 0 : entries.length
this.clear()
while (++index < length) {
const entry = entries[index]
this.set(entry[0], entry[1])
}
}
複製代碼
在 constructor
中並無看到初始化 __data__
屬性和 size
屬性,這個其實在 clear
方法中初始化了,後面會解釋。
接着遍歷傳入的二維數組,調用 set
方法,初始化緩存的值。將子項的第一項做爲 key
,第二項爲緩存的值。
clear() {
this.__data__ = Object.create(null)
this.size = 0
}
複製代碼
clear
的做用是清空緩存,所以須要將 size
重置爲 0
。
將緩存的數據 __data__
設置爲空對象。
這裏並無用 this.__data__ = {}
置空,而是調用了 Object.create
方法,而且將 null
做爲參數。咱們都知道, Object.create
的第一個參數爲建立對象的原型對象,傳入 null
的時候,返回的就是一個真空對象,即沒有原型的對象,所以不會有原型屬性的干擾,用來作緩存對象十分適合。
has(key) {
const data = this.__data__
return data[key] !== undefined
}
複製代碼
has
用來判斷是否已經有緩存數據,若是緩存數據已經存在,則返回 true
。
判斷也十分簡單,只須要判斷取出來的值是否爲 undefined
便可。
這個判斷有一個坑,後面會講到。
set(key, value) {
const data = this.__data__
this.size += this.has(key) ? 0 : 1
data[key] = value === undefined ? HASH_UNDEFINED : value
return this
}
複製代碼
set
用來增長或者更新須要緩存的值。set
的時候須要同時維護 size
和在緩存的值。
首先調用 has
方法,判斷對應的 key
是否已經被緩存過,若是已經緩存過,則 size
保持不變,不然 size
加 1
。
緩存值其實就是設置緩存對象 this.__data__
對應 key
屬性的值。
在 has
中說到用 data[key] !== undefined
有一個坑,由於要緩存的值也能夠是 undefined
,若是不作處理,確定會致使判斷錯誤。
lodash 的處理方式是將 undefined
的值轉換成 HASH_UNDEFINED
,也即一開始便定義的 __lodash_hash_undefined__
字符串來儲存。
因此在緩存中,是用字符串 __lodash_hash_undefined__
來替代 undefined
的。
set
在最後還將實例 this
返回,以支持鏈式操做。
get(key) {
const data = this.__data__
const result = data[key]
return result === HASH_UNDEFINED ? undefined : result
}
複製代碼
get
方法是從緩存中取值。
取值其實就是返回緩存對象中對應 key
的值便可。由於 undefined
在緩存中是以 __lodash_hash_undefined__
來表示的,所以遇到值爲 __lodash_hash_undefined__
時,返回 undefined
。
其實這樣仍是有小小的問題的,若是須要緩存的值恰好是 __lodash_hash_undefined__
,那取出來的值跟預設的就不一致了。可是這樣狀況應該不多出現吧。
delete(key) {
const result = this.has(key) && delete this.__data__[key]
this.size -= result ? 1 : 0
return result
}
複製代碼
delete
方法用來刪除指定 key
的緩存。成功刪除返回 true
, 不然返回 false
。 刪除操做一樣須要維護 size
屬性和緩存值。
首先調用 has
方法來判斷緩存是否存在,若是存在,用 delete
操做符將 __data__
中對應的屬性刪除。
delete
操做符在成功刪除屬性時會返回 true
,若是成功刪除,則須要將 size
減小 1
。
署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
最後,全部文章都會同步發送到微信公衆號上,歡迎關注,歡迎提意見:
做者:對角另外一面