如何为sessionStorage之类的东西编写一个合适的ES6包装器

时间:2017-09-20 13:35:35

标签: javascript es6-class proxy-pattern

您好我想知道如何为sessionStorage

之类的东西编写一个合适的包装器

我可以通过对sessionStorage的方法调用来实现我自己的类和代理。例如,使用一些快速伪代码:

class customStorage {
    set(key, value) {
        sessionStorage.setItem(key, value);
    }
}

我会像这样使用它:

const customStorage = new customStorage();
customStorage.set('my-key', 'hello there');

一切都很好,但是我希望用户可以自由地在我的代理上使用其他本地sessionStorage方法,而这些方法可能不会在我的代理中实现。

对于类似sessionStorage的内容,即使他们所做的一切都代理到sessionStorage而没有任何干预,也可以自己编写它们。

对于更大的地方,我只会操纵20种中的5种方法或其他东西,这似乎不可行。

用原型覆盖原生功能似乎也是导致许多wtfs-per-minute的死亡陷阱。

到目前为止,我从Javascript中的'代理模式'中读到了它们都实现了原始Object中的所有方法。我被迫这样做了吗?

是否有某种方法可以在构造函数中创建ES6类并将该类的原型设置为sessionStorage?

1 个答案:

答案 0 :(得分:2)

  

我希望用户可以自由地在我的代理上使用其他本地sessionStorage方法,而这些方法可能无法在我的代理中实现。

如果他打算这样做,我宁愿让用户直接使用本地sessionStorage 。您的实现确实有自己独立的功能,它在内部使用sessionStorage但不是sessionStorage。没有理由在您的对象上实现其接口。 (另见composition over inheritance)。

  

是否有某种方法可以创建ES6 class并在构造函数中将该类的原型设置为sessionStorage

没有。即使您想要实现该接口,您的对象也不是真正的SessionStorage实例。同样在这种特殊情况下,sessionStorage是一个单例,你不能实例化第二个SessionStorage,所以继承在这里绝对不起作用。

有三种方法可以解决这个问题(我将为通用案例编写代码,并从要包装的任意对象进行实例化,您可能需要一个类似于静态单例的自定义存储):

  • Mixins来装饰物体。不要创建另一个实例,只需覆盖原始属性。 (对于内置对象,这可能是不可能的)

    function custom(orig) {
        orig.get = function() { … };
        return orig;
    }
    
  • 寄生继承,使用对象的反射创建完整的包装。

    function custom(orig) {
        const obj = {
            get() { … };
        };
        for (const p in orig) { // assuming everything is enumerable - alternatively use
                                // for (const p of Object.getOwnPropertyNames(…))
                                // or even incorporating the prototype chain
            obj[p] = typeof orig[p] == "function"
              ? (...args) => orig[p](...args)
              : orig[p];
        }
        return obj;
    }
    
  • 带有suitable handler的文字Proxy

    const customMethods = {
        get() { … }
    };
    const handler = {
        has(target, name) {
            return name in customMethods || name in target;
        },
        get(target, name) {
            if (name in customMethods) return customMethods[name];
            else return target[name];
            // if its a native object with methods that rely on `this`, you'll need to
            // return target[name].bind(target)
            // for function properties
        }
    }
    
    function custom(orig) {
        return new Proxy(orig, handler);
    }