lodash源码分析之List缓存
2018-01-17 09:30
429 查看
昨日我沿着河岸/漫步到/芦苇弯腰喝水的地方
顺便请烟囱/在天空为我写一封长长的信
潦是潦草了些/而我的心意/则明亮亦如你窗前的烛光/稍有暧昧之处/势所难免/因为风的缘故
——洛夫《因为风的缘故》
本文为读 lodash 源码的第七篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
因此,在不支持
返回的结果如下:
结构和
《lodash源码分析之自减的两种形式》
这里调用
其实就是将容器
在之前的文章中已经介绍过,
跟
否则更新
强迫症看到
如果缓存中存在值,则返回缓存中的值,否则返回
首先调用
如果索引小于
如果要删除的缓存是缓存中的最后一项,则直接调用
为什么不直接都用
有兴趣的可以看下
从这里又看出了
最后将缓存数量
MDN: 使用对象
ECMAScript5.1中文版 + ECMAScript3 + ECMAScript(合集)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
顺便请烟囱/在天空为我写一封长长的信
潦是潦草了些/而我的心意/则明亮亦如你窗前的烛光/稍有暧昧之处/势所难免/因为风的缘故
——洛夫《因为风的缘故》
本文为读 lodash 源码的第七篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
作用与用法
在之前的《lodash源码分析之Hash缓存》介绍过用Hash做缓存的情况,在这篇文章中介绍过,lodash 是想要实现和
Map一样的接口。
Hash其实是用对象来做缓存,但是对象有一个局限,它的
key只能是字符串或者
Symbol类型,但是
Map是支持各种类型的值来作为
key,因此
Hash缓存无法完全模拟
Map的行为,当遇到
key为数组、对象等类型时,
Hash就无能为力了。
因此,在不支持
Map的环境下,
lodash实现了
ListCache来模拟,
ListCache本质上是使用一个二维数组来储存数据。
ListCache的调用方式和
Hash一致:
new ListCache([ [{key: 'An Object Key'}, 1], [['An Array Key'],2], [function(){console.log('A Function Key')},3] ])
返回的结果如下:
{ size: 3, __data__: [ [{key: 'An Object Key'}, 1], [['An Array Key'],2], [function(){console.log('A Function Key')},3] ] }
结构和
Hash类似,但是
__data__变成了数组。
接口设计
ListCache的接口与
Hash一样,同样实现了
Map的数据管理接口。
依赖
import assocIndexOf from './assocIndexOf.js'
《lodash源码分析之自减的两种形式》
源码分析
class ListCache { 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__ = [] this.size = 0 } delete(key) { const data = this.__data__ const index = assocIndexOf(data, key) if (index < 0) { return false } const lastIndex = data.length - 1 if (index == lastIndex) { data.pop() } else { data.splice(index, 1) } --this.size return true } get(key) { const data = this.__data__ const index = assocIndexOf(data, key) return index < 0 ? undefined : data[index][1] } has(key) { return assocIndexOf(this.__data__, key) > -1 } set(key, value) { const data = this.__data__ const index = assocIndexOf(data, key) if (index < 0) { ++this.size data.push([key, value]) } else { data[index][1] = value } return this } }
constructor
构造器跟Hash一模一样,都是先调用
clear方法,然后调用
set方法,往缓存中加入初始数据。
这里调用
clear方法并不是说为了清除数据,还没开始使用这个类,肯定是没有数据的,而是为了初始化
__data__和
size这两个属性。
clear
clear() { this.__data__ = [] this.size = 0 }
clear是为了清空缓存。
其实就是将容器
__data__设置成空数组,在
Hash中是设置为空对象,将缓存数量
size设置为
0。
has
has(key) { return assocIndexOf(this.__data__, key) > -1 }
has用来判断是否已经有缓存数据,如果缓存数据已经存在,则返回
true。
在之前的文章中已经介绍过,
assocIndexOf检测的是对应
key的
[key,value]数组在二维数组中的索引,其行为跟
indexOf一致,不存在于二维数组中时,返回
-1,否则返回索引值。因此可以用是否大于
-1来判断指定
key的数据是否已经被缓存。
set
set(key, value) { const data = this.__data__ const index = assocIndexOf(data, key) if (index < 0) { ++this.size data.push([key, value]) } else { data[index][1] = value } return this }
set用来增加或者更新需要缓存的值。
set的时候需要同时维护
size和缓存的值。
跟
has一样,调用
assocIndexOf找到指定
key的索引值,如果小于
0,则表明指定的
key尚未缓存,需要将缓存数量
size加
1,然后将缓存数据加入到
this.__data__的末尾。
否则更新
value即可。
强迫症看到
has用大于
-1来判断,而这里用小于
0来判断可能会相当难受。
get
get(key) { const data = this.__data__ const index = assocIndexOf(data, key) return index < 0 ? undefined : data[index][1] }
get方法是从缓存中取值。
如果缓存中存在值,则返回缓存中的值,否则返回
undefined。
delete
delete(key) { const data = this.__data__ const index = assocIndexOf(data, key) if (index < 0) { return false } const lastIndex = data.length - 1 if (index == lastIndex) { data.pop() } else { data.splice(index, 1) } --this.size return true }
delete方法用来删除指定
key的缓存。成功删除返回
true, 否则返回
false。 删除操作同样需要维护
size属性。
首先调用
assocIndexOf来找到缓存的索引。
如果索引小于
0,表明没有缓存,删除不成功,直接返回
false。
如果要删除的缓存是缓存中的最后一项,则直接调用
pop方法,将缓存删除,否则将调用
splice方法将对应位置的缓存删除。
为什么不直接都用
splice来删除数据呢?因为
pop的性能比
splice好,我简单测了一下,大概快
17%左右。
有兴趣的可以看下
pop和
splice的规范,
splice要比
pop做的事情要多。
从这里又看出了
lodash对性能的极致追求。
最后将缓存数量
size减少
1。
参考
Set 和 Map 数据结构MDN: 使用对象
ECMAScript5.1中文版 + ECMAScript3 + ECMAScript(合集)
License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
相关文章推荐
- lodash源码分析之List缓存
- lodash源码分析之Hash缓存
- lodash源码分析之缓存方式的选择
- lodash源码分析之Hash缓存
- lodash源码分析之缓存方式的选择
- Guava缓存器源码分析——缓存统计器
- LinkedList-源码分析
- List之LinkedList源码分析
- 容器源码分析之LinkedList(三)
- ecshop源码分析——用cookie缓存sql语句
- Caching-缓存架构与源码分析
- OkHttp 3.7源码分析(四)——缓存策略
- Java集合源码分析(三)LinkedList
- STL源码分析(2) -- list.h分析(1)
- Java集合框架成员之LinkedList类的源码分析(基于JDK1.8版本)
- list集合源码分析
- 容器第十课,迭代器遍历List和Set,List迭代器源码分析
- ArrayList和LinkedList部分源码分析性能差异
- Nginx 源码分析-- ngx_array、ngx_list基本数据结构
- Java-List源码分析