localStorage应用


前言

由于项目中,我们会经常使用localStorage去进行存储,可能会存token信息背景主题路由参数……,接下来总结一下localStorage的拓展用法或者是面试官喜欢问的点

使用

下面列出一些常用的api供大家参考

localStorage.setItem(key,value)新增数据

localStorage.getItem(key)取数据

localStorage.removeItem(key)移除数据

localStorage.clear()清空数据

localStorage设置时效性

面试官:我们都知道localStorage必须我们手动去清除数据,那我们怎么设置时效性呢?

我们其实可以通过给localStorage设置数据时,我们去添加一个时间戳,并且我们在getItem的时候我们可以根据之前设置的时间戳,进行判断我们需不需要把这个数据清除或者其他操作

根据我们Date实例对象上的getTime方法(详情见mdn官方文档这里不详细说明)并且我们的时间是一个毫秒的单位,将getItem的时间和setItem相减判断

  • 封装一下setItem时候的函数
const set = () => {
    const now = new Date().getTime();
    localStorage.setItem("key", JSON.stringify({ value: "data", time: now }));
}

q3MEhq.png

  • 封装一下getItem时候的函数

我们首先拿到key所对应的value值,并且去找到之前设置的一个时间,并且拿到此时的时间,和传入的时间做对比就可以啦,过期的话就直接把key删掉就可以,没过期的话,根据情况是否要更新时间全看自己了,注意:时间传入的值是毫秒为单位的,若设置1000,则是有效期1秒

const get = (key, time) => {
    const localData = localStorage.getItem(key);
    if (!localData) return "";
    const localDataObj = JSON.parse(localData);
    const nowTime = new Date().getTime();
    const localDataTime = localDataObj.time || nowTime;
    if (nowTime - localDataObj.time > time) {
        console.log("数据已过期");
        // 删除
        localStorage.removeItem(key);
        return false;
    } else {
        if (!localDataObj.data) return "";
        const data = JSON.parse(localDataObj.data);
        return data;
    }
};
set() //调用函数set
get(key,1000) // 此时的1000指的是1s喔
get(key,1000 * 60 )

若localStorage存在多个无效key怎么办

面试官:会不会有存在多少个无效key的情况呢?若是有的话我们怎么解决?或者说我们现在最多能让localStorage最多存储10个key,我们怎么根据我们最少使用的这么一个key把他删掉,在添加一个新的key呢?

我:……轮询去查看localStorage,并且设置个标志位count,每当我们getItem的时候我们count++,当数量到达十个的时候,我们遍历这10个key看他的一个count数量(回答到这的时候感觉回答的还是可以的只是自我感觉而已)

面试官:那也有问题,如果我们第一天访问key11次,我们第二天访问key1100次,我们第三天访问key2200次,key1访问10次,那我们还是会把key1删掉啊

我:(面试官反应好快)啊这……那我们可以传一个时间戳进行判断呀

面试官:可以不用时间戳呢,还有其他办法

我:实在不会了……

其实此刻的面试官其实想问的是我们的LRU算法,也就是最近最少使用算法(力扣:LRU算法)

我们可以利用javascript的数据结构Map,因为我们的Map插入是个有序的,并且我们的操作复杂度为O(1)

我们插入数据的时候,若有旧数据需要把旧数据保存再进行删除,重新set一遍处于底部的位置,并且要判断是否超过你最大的一个容量,若超过容量的话把头部的数据删掉

访问的时候,我们也会把数据重新插入到底部,和插入数据其实原理是一样的

class LRUCache {
    constructor(capacity) {
        this.capacity = capacity;
        this.map = new Map();
    }
    get(key) {
        if (this.map.has(key)) {
            // get表示访问该值
            // 所以在访问的同时,要将其调整位置,放置在最后
            const temp = this.map.get(key);
            // 先删除,再添加
            this.map.delete(key);
            this.map.set(key, temp);
            // 返回访问的值
            return temp;
        } else {
            // 不存在,返回-1
            return -1;
        }
    }
    put(key, value) {
        // 要将其放在最后,所以若存在key,先删除
        if (this.map.has(key)) this.map.delete(key);
        // 设置key、value
        this.map.set(key, value);
        if (this.map.size > this.capacity) {
            // 若超出范围,将map中头部的删除
            // map.keys()返回一个迭代器
            // 迭代器调用next()方法,返回包含迭代器返回的下一个值,在value中
            this.map.delete(this.map.keys().next().value);
        }
    }
}

怎么测试localStorage大小

面试官:那我们怎么判断localStorage的大小呢?

我:(思考了一波)我们可以利用累加的方法……诶?(妈的好像有点不太对……本来想说一直累加数据直到我们不能累加为止)

面试官:……

面试官:其实就是我们一直加数据+我们的错误处理,直到localStorage不能添加为止

我:对对,我刚刚想的就是这个……

首先我们要先对localStorage有一些基本了解,这里就不细讲了

  • localStorage存储的键和值始终采用UTF-16 DOMString格式
  • 5M的单位就是字符串的长度,而不是字符数
  • localStorage的键占不占空间??占空间

这个其实可以根据一个简单的例子来证明:

  • 我们把 key和val各自设置长 2.5M的长度
  • 此时我们把键值 +0.1
const charTxt = "a";
let count = (2.5 * 1024 * 1024);
let content = new Array(count).fill(charTxt).join("") + 0.1; //+0.1
const key = new Array(count).fill(charTxt).join("");
localStorage.clear();
try {
    console.time("setItem")
    localStorage.setItem(key, content);
    console.timeEnd("setItem")
} catch (err) {
    console.log("err", err);
}

下面为报错的详情

  • 若我们此时把我们value -0.1,其实是可以运行的,小伙伴可以试一下!

q3NeIO.png

这个方法其实就是测试localStorage大小的方法

结语

上面总结的问题也是最近春招被问得比较多的问题,也学习到蛮多东西的!

如果你觉得此文对你有一丁点的帮助,点个赞!


文章作者: Daniel Lin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Daniel Lin !
  目录