Z2bBKA7Xh

23朵毒蘑菇

storageX 1.2,细节和性能优化,源码加上了注释,很好理解。

原文章迁移

storageX

2021-03-30 10:38:40 已有版本 1 个 show:0.53kTYPE: blog

storageX 1.2 ,用法和之前差不多,只是有一点区别。性能等方面进行了优化。

修复BUG

1:储存的是数组时,取出来重新赋值会丢失map,filter等自带的方法。原因:json化数据时触发了代理的set属性,会调用clone方法,因为当时考虑到数据的储存简单clone一下就行,现在删除了clone。bug解决。
2:直接调用localStorageX()生成对象从而控制键值,以及更深层次的值,我认为这样不好。解决:取消深层代理。

使用方法。

1:只是对键值进行操作
const localStorage= localStorageX();
localStorage.a = {b:1};  //'a' 对应的值 {'b':'1'}
//旧版:localStorage.a.b = 2  'a' 对应的值 {'b':'2'}
localStorage.a.b = 2  //无效,不允许深度修改
//需要这样
localStorage.a = {b:2};
2:深度的对象化存储(单纯的只对值进行操作)
//因为考虑到如果需要深度代理那么值一定是个对象
let state = {
    a:1,
    b:{
        c:3,
    },
};
state = localStorageX(
    "state",  //本地储存对应的键
    state,  //初始化的值,如果该键有数据且为对象时优先代理
);
//当state的属性发生变化时会相应的将state存储到本地。
state.a = 1;
state.a = {b:{c:{d:2}}};
state.a.c.d = 3;
console.log(state.a.c.d);  //打印 3
//只针对值为对象时,而且只会对该对象属性进行修改添加,也就是说像下面这样不管用
state = null;
state = 1;
state = {a:1};
//了解js基础都知道,这样只是改变该变量的指向,并不是对原对象进行修改。
//如果想修改键的值请使用上面的那种方法。

皆不支持函数式储存,因为函数无法JSON化,既然是数据的话为什么要存函数呢?

下面是源码

可以根据自己自行定制

/*
    storageX 1.2 storage对象化储存
    不支持function的储存
    不支持对象的迭代
    https://www.dumogu.top/bloginfo/8661a212e0
*/
/*jshint esversion: 9 */
//将字符串转化为 对象 || 其他数据格式
function stringToObject(value){
    try {
        return JSON.parse(value);
    } catch(e) {
        if(value === 'undefined') return undefined;  //排除无法转换undefined的情况
        return value;
    }
}
//根据键名清空
function removeItem(key,mode='local'){
    if(mode === "local"){
        localStorage.removeItem(key);
    }else{
        sessionStorage.removeItem(key);
    }
}
//根据键名写入(转化为字符串)
const taskList = {};  //任务队列
function setItem(key,value,mode='local'){
    if(typeof key !== "string" || !key) throw "key 必须是字符串 || key 不能为空";
    if(typeof value == "function") throw "value 不能是function";
    //性能优化,防止频繁操作 (针对大数据会有明显加快,小数据可能会花费更多的时间)
    clearTimeout(taskList[key+mode]);  //取消任务
    taskList[key+mode] = setTimeout(()=>{
        if(mode === "local"){
            localStorage.setItem(key,JSON.stringify(value));
        }else{
            sessionStorage.setItem(key,JSON.stringify(value));
        }
    },0);
}
//根据键名获取(转化为对象)
function getItem(key,mode='local'){
    if(mode === "local"){
        return stringToObject(localStorage.getItem(key));
    }else{
        return stringToObject(sessionStorage.getItem(key));
    }
}
//深层对象代理(<目标对象>,<统一的set回调函数>)
function deepProxy(target,setFn){
    if(typeof target == "function") throw "target 不能是function";
    if(!(target instanceof Object)) return target;
    for(let index in target){
        if(target[index] instanceof Object){  //如果是对象的话转成代理对象
            target[index] = deepProxy(target[index],setFn);
        }
    }
    return new Proxy(
        target,
        {
            set(_target,_key,_value){
                if(_value instanceof Object){  //如果是对象的话转成代理对象
                    //需要克隆防止引用对象被修改时影响到代理对象 没有克隆(数据进行json化时会触发监听进行赋值函数,不克隆比较好)
                    _value = deepProxy(_value,setFn);
                }
                let r = Reflect.set(_target, _key, _value);
                setFn();
                return r;
            },
            deleteProperty(_target, _key) {
                let r = Reflect.deleteProperty(_target, _key);
                setFn();
                return r;
            }
        },
    );
}
//storage本地储存对象化代理,只有两种模式(只针对数据)
function storageX(key,target={},mode="local"){
    if(typeof target == "function") throw "target 不能是function";
    if(!key){  //表示代理整个localStorage (key表示localStorage的key,不深度代理)
        const pass = {};  //已经访问过的属性
        return new Proxy(
            {},
            {
                get(_target,_key){  //获取某个键的值
                    if(typeof _key !== "string") throw "key 必须是字符串";
                    if(_key === "removeItem") return removeItem;  //返回清除方法
                    if(!pass[_key]){
                        _target[_key] = getItem(_key,mode);
                        pass[_key] = true;
                    }
                    return _target[_key];
                },
                set(_target,_key,_value){  //写入某个键的值
                    if(_key === "removeItem") throw "removeItem是内置属性,不能更改";  //添加清除方法
                    let r = Reflect.set(
                        _target, 
                        _key, 
                        _value,
                    );
                    setItem(_key,_value,mode);
                    return r;
                },
            },
        );
    }else{  //表示代理一个键,对应一个对象(深度代理)
        if(typeof key !== "string") throw "key 必须是字符串";
        if(!(target instanceof Object)) throw "target 必须是对象";
        let oldTarget = getItem(key,mode);
        if(!oldTarget){
            setItem(key,target,mode);  //初始化
        }else{
            target = oldTarget;  //如果键中有值则以该值为准
            if(!(target instanceof Object)) throw "localStorage key中有原始值且不能转化为对象";
        }
        return deepProxy(
            target,
            function(){
                setItem(key,target,mode);
            },
        );
    }
}
//localStorage模式
function localStorageX(key,target){
    return storageX(key,target,'local');
}
//sessionStorage模式
function sessionStorageX(key,target){
    return storageX(key,target,'session');
}
export {
    localStorageX,
    sessionStorageX,
};