lodash源码分析之Hash缓存
2018-01-02 08:44
531 查看
在那小小的梦的暖阁,我为你收藏起整个季节的烟雨。
——洛夫《灵河》
本文为读 lodash 源码的第四篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
作用与用法
Hash顾名思义,就是要有一个离散的序列,根据
key来储取数据。而在 javascript 中,最适合的无疑是对象了。
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__的对象中。
Hash与Map
后面将会讲到,除了使用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
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
clear() { this.__data__ = Object.create(null) this.size = 0 }
clear的作用是清空缓存,因此需要将
size重置为
0。
将缓存的数据
__data__设置为空对象。
这里并没有用
this.__data__ = {}置空,而是调用了
Object.create方法,并且将
null作为参数。我们都知道,
Object.create的第一个参数为创建对象的原型对象,传入
null的时候,返回的就是一个真空对象,即没有原型的对象,因此不会有原型属性的干扰,用来做缓存对象十分适合。
has
has(key) { const data = this.__data__ return data[key] !== undefined }
has用来判断是否已经有缓存数据,如果缓存数据已经存在,则返回
true。
判断也十分简单,只需要判断取出来的值是否为
undefined即可。
这个判断有一个坑,后面会讲到。
set
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
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
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。
参考
Set 和 Map 数据结构Object.create()
License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
相关文章推荐
- lodash源码分析之Hash缓存
- lodash源码分析之List缓存
- lodash源码分析之List缓存
- lodash源码分析之缓存方式的选择
- lodash源码分析之缓存方式的选择
- 通过源码分析MyBatis的缓存
- Nginx源码分析---hash结构ngx_hash_t(v1.0.4)
- 集合框架源码分析五之LinkedHashMap,LinkedHashSet
- Mybatis3源码分析(17)-Sql解析执行-缓存的实现
- Spark源码分析之HashShuffle读写流程
- Guava缓存器源码分析——CacheBuilder
- shiro源码分析篇4:自定义缓存
- String.valueOf Long.valueOf Integer.valueOf 源码分析 缓存
- Linux内核源码分析-页高速缓存-address_space
- spark core源码分析11 RDD缓存及checkpoint
- ABP源码分析十三:缓存Cache实现
- Redis 源码分析(二) 一个 rehash 也不阻塞的哈希表
- nginx源码分析—hash结构ngx_hash_t(v1.0.4)
- 一步步学习 MyBatis:缓存的使用及源码分析
- 【Android开源项目分析】android轻量级开源缓存框架——ASimpleCache(ACache)源码分析