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,
};