Javascript 会话存储代理类作用域

Javascript 会话存储代理类作用域,javascript,ecmascript-6,es6-class,sessionstorage,es6-proxy,Javascript,Ecmascript 6,Es6 Class,Sessionstorage,Es6 Proxy,我想知道如何从自定义方法中访问本机会话存储范围 我的例子是: 在第3行,我希望在对数据执行变异后,能够代理到我的本机会话存储 但我如何再次访问该范围?我知道我可以打电话: sessionStorage.setItem 但这仅仅是因为它是全球可用的,而且这样做感觉是错误的。主要是因为我还想知道如何在没有全局可用的对象的情况下执行此操作,以便学习如何代理其他对象。一些窗口对象(如location)是只读的,在其上创建抽象或利用DI进行可测试性可能会很有用 会话存储应该按原样使用。通常不需要对其进行抽

我想知道如何从自定义方法中访问本机会话存储范围

我的例子是:

在第3行,我希望在对数据执行变异后,能够代理到我的本机会话存储

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

sessionStorage.setItem

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

一些窗口对象(如location)是只读的,在其上创建抽象或利用DI进行可测试性可能会很有用

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

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

自定义类或对象只能包装原始sessionStorage方法。由于存储API很小,包装类产生约20行代码:

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

  getItem(key) {
    return sessionStorage.getItem(key);
  }
  ...
}
sessionStorage对象是外来的。虽然它从存储中继承,但存储不是构造函数,sessionStorage方法应该直接绑定到sessionStorage,因此不可能仅使用CustomSessionStorage.prototype=sessionStorage。此外,sessionStorage还有一个长度属性描述符,也应该绑定该描述符

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

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
}
有些窗口对象(如location)是只读的,在其上创建抽象或利用DI实现可测试性非常有用

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

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

自定义类或对象只能包装原始sessionStorage方法。由于存储API很小,包装类产生约20行代码:

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

  getItem(key) {
    return sessionStorage.getItem(key);
  }
  ...
}
sessionStorage对象是外来的。虽然它从存储中继承,但存储不是构造函数,sessionStorage方法应该直接绑定到sessionStorage,因此不可能仅使用CustomSessionStorage.prototype=sessionStorage。此外,sessionStorage还有一个长度属性描述符,也应该绑定该描述符

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

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数据并解析它,我90%的时间都会得到一个项目,我不会每次都这样做。我只是想让我的proxylayer来处理这个问题。我不认为这里真的需要代理。这可以由常规类或对象来处理,因为存储应该是单例的。关于最初的问题,如何再次访问该范围?您需要在setItem中显式地将其称为sessionStorage.setItem。您可以在代理方法中使用此选项,但只有在以不同方式调用方法时才可以使用此选项:setk,v{this.setItema,msg}。如果您只是简单地包装原始方法,您还必须实现所有方法,如果您希望其行为类似于本机sessionStorage对象。是的。这并不难,这是在自定义存储中通常采用的方法,正如您所看到的,只有5种方法和长度属性。存储非常特殊,限制了它的扩展方式。如果你想扩展原来的方法,代理并不能使它变得更容易。@PatrickRoberts确实如此。我猜OP试图为存储创建一个方便的包装器,这样它就可以自动序列化和反序列化对象。如果我想为本机对象实现自定义方法,但不想实现所有这些方法,我需要一个代理。没有别的办法。如果我想在任何时候设置JSON.stringify数据并解析它,我90%的时间都会得到一个项目,我不会每次都这样做。我只是想让我的proxylayer来处理这个问题。我不认为这里真的需要代理。这可以由常规类或对象来处理,因为存储应该是单例的。关于最初的问题,如何再次访问该范围?您需要在setItem中显式地将其称为sessionStorage.setItem。您可以在代理方法中使用它,但只有在以不同方式调用方法时才可以使用:setk,v{this.setItema,msg}
e本机会话存储对象。是。这并不难,这是在自定义存储中通常采用的方法,正如您所看到的,只有5种方法和长度属性。存储非常特殊,限制了它的扩展方式。如果你想扩展原来的方法,代理并不能使它变得更容易。@PatrickRoberts确实如此。我猜OP试图为存储创建一个方便的包装器,以便能够自动序列化和反序列化对象。