【问题标题】:sessionStorage proxy class scopesessionStorage 代理类范围
【发布时间】:2017-09-21 08:52:58
【问题描述】:

我想知道如何从我的自定义方法中访问本机 sessionStorage 范围。

我的例子:

https://jsfiddle.net/3mc7ao7j/1/

在第 3 行,我希望在对数据执行突变后能够代理到我的本地 sessionStorage

我如何再次访问该范围?我知道我可以打电话:

sessionStorage.setItem()

但这很有效,因为它是全球可用的,这样做感觉不对。主要是因为我还想知道如何在没有全局可用的对象的情况下执行此操作,以便我可以学习如何代理其他对象。

【问题讨论】:

    标签: javascript ecmascript-6 es6-class sessionstorage es6-proxy


    【解决方案1】:

    location 这样的一些window 对象是只读的,在它们之上创建抽象或利用DI 来实现可测试性会很有用。

    sessionStorage 应该按原样使用。通常不需要对其进行抽象。如果需要扩展或修改其功能,则可以创建自定义类。可以实现Storage接口,也可以有自己的接口。

    在这里使用Proxy 是不合理的。它很慢并且限制了代码在 ES5 环境中的使用。

    自定义类或对象可以只包装原始的sessionStorage 方法。由于 Storage API 很小,因此包装类需要大约 20 行代码:

    class CustomSessionStorage {
      get length() {
        return sessionStorage.length;
      }
    
      getItem(key) {
        return sessionStorage.getItem(key);
      }
      ...
    }
    

    sessionStorage 对象是奇异的。虽然它继承自Storage,但Storage 不是构造函数,并且sessionStorage 方法应该直接绑定到sessionStorage,因此不能使其仅与CustomSessionStorage.prototype = sessionStorage 一起工作。此外,sessionStorage 还具有应绑定的 length 属性描述符。

    一种更通用的扩展方式是提供一个封装原始方法并可以进一步扩展的基类:

    function BaseSessionStorage() {}
    
    for (let prop of Object.getOwnPropertyNames(Storage.prototype)) {
      if (typeof sessionStorage[prop] === 'function') {
        // bind all sessionStorage methods
        BaseSessionStorage.prototype[prop] = sessionStorage[prop].bind(sessionStorage);
      } else {
         // a proxy for other props, length is read-only getter
         Object.defineProperty(BaseSessionStorage.prototype, prop, {
           get: () => sessionStorage[prop],
           set: val => { sessionStorage[prop] = val }
         });
      }
    }
    
    class CustomSessionStorage extends BaseSessionStorage {
      getItem(key) {
        return super.getItem(key);
      }
      // the rest of API is inherited
    }
    

    【讨论】:

    • 如果我想为本地对象实现自定义方法但不想实现所有这些方法,我需要一个代理。没有其他办法。如果我想在设置某些东西时使用JSON.stringify 数据并且JSON.parse 它得到我得到一个项目,90% 的时间我不会每次都这样做。我只是想让我的代理层来处理这个问题。
    • 我认为这里不需要代理。这可以由常规类(或者可能是对象,因为存储应该是单例)来处理。关于最初的问题,我如何再次访问该范围?,您需要在 setItem 中明确地将其称为 sessionStorage.setItem()。您可以在代理方法中使用this,但前提是方法的调用方式不同:set(k, v) { this.setItem(a, msg) }
    • 如果你只是简单地包装原始文件,如果你想让它表现得像原生 sessionStorage 对象,你还必须实现所有方法。
    • 是的。这并不难,这就是它通常在自定义存储中完成的方式,如您所见,只有 5 个方法和length prop。 Storage 非常特殊,并且限制了它可以扩展的方式。如果您想扩展原始方法,Proxy 并没有让事情变得更容易。
    • @PatrickRoberts 是的。我猜 OP 试图为存储做一个方便的包装器,所以它可以自动序列化和反序列化对象。
    猜你喜欢
    • 1970-01-01
    • 2012-04-02
    • 2014-10-15
    • 1970-01-01
    • 2016-03-13
    • 2011-07-03
    • 1970-01-01
    • 2016-11-17
    • 1970-01-01
    相关资源
    最近更新 更多