二次封装前端本地存储localStorage与sessionStorage

4 篇文章 0 订阅

使用typescript进行了二次封装,"typescript": "5.2.2"。下有编译好的js代码。


目录

应用场景

一、ts代码

二、编译js

1.代码

 2.使用方式

总结

应用场景

        同源下多个应用进行存储隔离

一、ts代码

"use strict";

// @ts-check

/**
 * @description: 装饰器:检查函数入参类型
 * @param {string | string[]} type 基本数据类型 || 基本数据类型集合
 */
function checkType(type: string | string[]) {
    return function (value: Function, { kind, name }) {
        return function (...args: any[]) {
            if (Array.isArray(type)) {
                args.forEach((item, index) => {
                    if (typeof item !== type[index]) {
                        throw new Error(`${kind}: ${name} params[${index}] is not ${type[index]}`);
                    }
                })
            } else {
                args.forEach((item, index) => {
                    if (typeof item !== type) {
                        throw new Error(`${kind}: ${name} params[${index}] is not ${type}`);
                    }
                })
            }
            return value.call(this, ...args);
        };
    }
}
/**
 * @description: 装饰器:限制参数长度
 * @param {number} extent 必传参数长度
 */
function limit(extent: number) {
    return function (value: Function, { kind, name }) {
        return function (...args: any[]) {
            if (args.length < extent) {
                throw new Error(`${kind}: ${name} Expect ${extent} parameters, actual ${args.length}`);
            }
            return value.call(this, ...args);
        };
    }
}

abstract class Base {
    public original: Storage;
    protected prefix: string;
    constructor(original: Storage, prefix: string) {
        this.original = original;
        this.prefix = prefix;
    }
    protected getKey(key: string): string {
        return `${this.prefix}_${key}`;
    }
}

class WebStorage extends Base {
    constructor(original: Storage, prefix: string) {
        super(original, prefix);
    }
    @limit(1)
    @checkType("string")
    public getItem(key: string): string | null {
        const data = this.original.getItem(this.getKey(key));
        if (data === null) return null;
        try {
            const { value, indate } = JSON.parse(data);
            if (indate === null) return value;
            if (indate >= Date.now()) {
                return value;
            } else {
                this.removeItem(key);
                return null;
            }
        } catch (error) {
            return data;
        }
    }
    /**
     * @description: 调用存储
     * @param {string} key 键
     * @param {string} value 值
     * @param {timestamp} indate 时间戳-键值有效时间
     */
    @limit(2)
    @checkType(["string", "string", "number"])
    public setItem(key: string, value: string, indate?: number): void {
        this.original.setItem(
            this.getKey(key),
            JSON.stringify({
                value: value,
                indate: indate ? Date.now() + indate : null
            })
        );
    }
    @limit(1)
    @checkType("string")
    public removeItem(key: string): void {
        this.original.removeItem(this.getKey(key));
    }
    public clear(): void {
        this.original.clear();
    }
}

export default WebStorage;

代码不过多解释,不复杂,还有注释。 

使用了新版ts装饰器,这也是我第一次尝试,据说性能更棒。

二、编译js

1.代码

"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
    var useValue = arguments.length > 2;
    for (var i = 0; i < initializers.length; i++) {
        value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
    }
    return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
    function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
    var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
    var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
    var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
    var _, done = false;
    for (var i = decorators.length - 1; i >= 0; i--) {
        var context = {};
        for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
        for (var p in contextIn.access) context.access[p] = contextIn.access[p];
        context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
        var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
        if (kind === "accessor") {
            if (result === void 0) continue;
            if (result === null || typeof result !== "object") throw new TypeError("Object expected");
            if (_ = accept(result.get)) descriptor.get = _;
            if (_ = accept(result.set)) descriptor.set = _;
            if (_ = accept(result.init)) initializers.unshift(_);
        }
        else if (_ = accept(result)) {
            if (kind === "field") initializers.unshift(_);
            else descriptor[key] = _;
        }
    }
    if (target) Object.defineProperty(target, contextIn.name, descriptor);
    done = true;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-check
/**
 * @description: 装饰器:检查函数入参类型
 * @param {string | string[]} type 基本数据类型 || 基本数据类型集合
 */
function checkType(type) {
    return function (value, _a) {
        var kind = _a.kind, name = _a.name;
        return function () {
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            if (Array.isArray(type)) {
                args.forEach(function (item, index) {
                    if (typeof item !== type[index]) {
                        throw new Error("".concat(kind, ": ").concat(name, " params[").concat(index, "] is not ").concat(type[index]));
                    }
                });
            }
            else {
                args.forEach(function (item, index) {
                    if (typeof item !== type) {
                        throw new Error("".concat(kind, ": ").concat(name, " params[").concat(index, "] is not ").concat(type));
                    }
                });
            }
            return value.call.apply(value, __spreadArray([this], args, false));
        };
    };
}
/**
 * @description: 装饰器:限制参数长度
 * @param {number} extent 必传参数长度
 */
function limit(extent) {
    return function (value, _a) {
        var kind = _a.kind, name = _a.name;
        return function () {
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            if (args.length < extent) {
                throw new Error("".concat(kind, ": ").concat(name, " Expect ").concat(extent, " parameters, actual ").concat(args.length));
            }
            return value.call.apply(value, __spreadArray([this], args, false));
        };
    };
}
var Base = /** @class */ (function () {
    function Base(original, prefix) {
        this.original = original;
        this.prefix = prefix;
    }
    Base.prototype.getKey = function (key) {
        return "".concat(this.prefix, "_").concat(key);
    };
    return Base;
}());
var WebStorage = function () {
    var _a;
    var _classSuper = Base;
    var _instanceExtraInitializers = [];
    var _getItem_decorators;
    var _setItem_decorators;
    var _removeItem_decorators;
    return _a = /** @class */ (function (_super) {
            __extends(WebStorage, _super);
            function WebStorage(original, prefix) {
                var _this = _super.call(this, original, prefix) || this;
                __runInitializers(_this, _instanceExtraInitializers);
                return _this;
            }
            WebStorage.prototype.getItem = function (key) {
                var data = this.original.getItem(this.getKey(key));
                if (data === null)
                    return null;
                try {
                    var _b = JSON.parse(data), value = _b.value, indate = _b.indate;
                    if (indate === null)
                        return value;
                    if (indate >= Date.now()) {
                        return value;
                    }
                    else {
                        this.removeItem(key);
                        return null;
                    }
                }
                catch (error) {
                    return data;
                }
            };
            /**
             * @description: 调用存储
             * @param {string} key 键
             * @param {string} value 值
             * @param {timestamp} indate 时间戳-键值有效时间
             */
            WebStorage.prototype.setItem = function (key, value, indate) {
                this.original.setItem(this.getKey(key), JSON.stringify({
                    value: value,
                    indate: indate ? Date.now() + indate : null
                }));
            };
            WebStorage.prototype.removeItem = function (key) {
                this.original.removeItem(this.getKey(key));
            };
            WebStorage.prototype.clear = function () {
                this.original.clear();
            };
            return WebStorage;
        }(_classSuper)),
        (function () {
            var _b;
            var _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
            _getItem_decorators = [limit(1), checkType("string")];
            _setItem_decorators = [limit(2), checkType(["string", "string", "number"])];
            _removeItem_decorators = [limit(1), checkType("string")];
            __esDecorate(_a, null, _getItem_decorators, { kind: "method", name: "getItem", static: false, private: false, access: { has: function (obj) { return "getItem" in obj; }, get: function (obj) { return obj.getItem; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _setItem_decorators, { kind: "method", name: "setItem", static: false, private: false, access: { has: function (obj) { return "setItem" in obj; }, get: function (obj) { return obj.setItem; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(_a, null, _removeItem_decorators, { kind: "method", name: "removeItem", static: false, private: false, access: { has: function (obj) { return "removeItem" in obj; }, get: function (obj) { return obj.removeItem; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        })(),
        _a;
}();
exports.default = WebStorage;

 2.使用方式

import WebStorage from "./webStorage.js";

const prefix = "projectName";

const customStorage = {
  localStorage: new WebStorage(window.localStorage, prefix),
  sessionStorage: new WebStorage(window.sessionStorage, prefix)
};

customStorage.localStorage.setItem("test1", "a");
console.log(customStorage.localStorage.getItem("test1"));

customStorage.localStorage.setItem("test2", "b", 3000);
console.log(customStorage.localStorage.getItem("test2"));
setTimeout(() => {
  console.log(customStorage.localStorage.getItem("test2"))
}, 5000);

基本对标原生态的使用方式,传参类型更严格,新增了存储过期的能力,使用无过多心智开销。 项目支持ts就用ts,仅支持js就用编译好的js,一样滴。使用方式建议挂载在一个公共的对象上,进行向下分发,不进行多次初始化。 


总结

觉得写的有问题的地方可以自己修改ts代码,重新使用typescript编译成js,欢迎大佬们评论区指点错误。如果有更好应对该场景的解决方案,留下链接让我学习一下。😁

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值