How to encapsulate an Storage using the idea of Vue

  • 2021-11-10 08:52:53
  • OfStack

Directory background
Functional purpose
Source of ideas
Implementing set
get
deleteProperty
preventExtensions
has
Summarize

Background

localStorage, sessionStorage, these two API are our front-end daily development storage tools, we often use them to store some data. When we operate them everyday, the use of localStorage and sessionStorage is generally direct:


localStorage.setItem(xxx, xxx);
sessionStorage.setItem(xxx, xxx);
localStorage.getItem(xxx);
sessionStorage.getItem(xxx);

Or some students will simply package 1:


const getItem = (key) => {
   const serializedValue = window.localStorage.getItem(key) as any;
   return JSON.parse(serializedValue);
};
const setItem = (key, value) => {
  if (window && window.localStorage) {
    window.localStorage.setItem(key, JSON.stringify(value));
  }
};

However, although it is not a big problem to use this way, it always feels that the code is not elegant enough. Just recently, it encapsulated some underlying basic libraries, including the encapsulation of two brothers. I found something interesting. This site also has some new experiences and ideas to share with you.

Function

localStorage, sessionStorage Settings localStorage, sessionStorage get localStorage, sessionStorage delete 1 item localStorage, sessionStorage Empty All Storage

Purpose

Encapsulate one localStorage, sessionStorage API to add, delete, modify and check storage.

Source of ideas

If you have used Vue2.0, you must know the Object. defineProperty method. This API is the core of Vue response, which is used to observe data changes, but it has one drawback:

When adding a new pair of key/value or deleting an existing pair of key/value to the object type data, it cannot be observed, which leads to the inability to notify dependencies and drive the view to update responsively when adding or deleting values to object data. Array change detection is implemented by Vue2.0 through interceptors, that is to say, as long as the array is operated by the method on the array prototype, it can be detected, but the data is operated by the subscript of the array, which needs to be operated manually.

These problems were solved in Vue 3.0, and the solution was Proxy in ES 6.

Proxy is used to modify the default behavior of some operations, which is equivalent to making modifications at the language level, so it belongs to a kind of "metaprogramming" (meta programming), that is, programming the programming language.

Proxy can be understood as setting up a layer of "interception" before the target object, and the external access to the object must pass through this layer first, so it provides a mechanism to filter and rewrite the external access. The word Proxy, which originally means agent, is used here to mean that it "proxies" certain operations, and can be translated as "agent".

Proxy is a natural interceptor and proxy, so we can also use Proxy to proxy the operation of localStorage and sessionStorage. Don't say much, just go to the code.

Realization


var proxyStorage = {
  /**
   *  Return  Storage  Agent 
   * @returns Proxy
   * @example
   * proxyStorage.getStorageProxy(localStorage, '_')
   */
  getStorageProxy: (storage, prefix) => {
    if (!storage)
      return false;
    const getKey = (prop) => `${prefix}.${String(prop)}`;
    return new Proxy(new Object(), {
      /**
       *  Settings  storage
       * @returns boolean
       * @example
       * const storageProxy = proxyStorage.getStorageProxy(localStorage, '_');
       * storageProxy.a = 1;
       */
      set(target, prop, value) {
        target[prop] = value;
        storage.setItem(getKey(prop), JSON.stringify(value));
        return true;
      },
      /**
       *  Get  storage
       * @returns boolean
       * @example
       * const storageProxy = proxyStorage.getStorageProxy(localStorage, '_');
       * console.log(storageProxy.a);
       */
      get(_, prop) {
        return JSON.parse(storage.getItem(getKey(prop)) || '');
      },
      /**
       *  Delete  storage
       * @returns boolean
       * @example
       * const storageProxy = proxyStorage.getStorageProxy(localStorage, '_');
       * delete storageProxy.a;
       */
      deleteProperty(_, prop) {
        storage.removeItem(getKey(prop));
        return true;
      },
      /**
       *  Empty  storage
       * @returns boolean
       * @example
       * const storageProxy = proxyStorage.getStorageProxy(localStorage, '_');
       * Object.preventExtensions(storageProxy);
       */
      preventExtensions(target) {
        Object.preventExtensions(target);
        storage.clear();
        return true;
      },
      /**
       *  Query  storage
       * @returns boolean
       * @example
       * const storageProxy = proxyStorage.getStorageProxy(localStorage, '_');
       * 'a' in storageProxy;
       */
      has(target, prop) {
        try {
          return !!storage.key(prop);
        } catch (error) {
          return false;
        }
      }
    });
  },
};

var proxyStorageTest = proxyStorage.getStorageProxy(localStorage, '_');

Using Proxy, a proxy object of localStorage and sessionStorage is returned, which hijacks operations such as set, get, delete, preventExtensions and in.

set

Settings of intercepting object properties, such as storage. foo = v or storage ['foo'] = v, return 1 Boolean value. Assign a value to the attribute of the proxy object, intercept this assignment, and operate setItem of the corresponding storage, so that the value can be directly stored in the corresponding storage.


storage.a = 1;
// or
storage['a'] = 1;

get

Intercept the reading of object properties, such as storage. foo and storage ['foo']. Read the attribute value of the proxy object, intercept the fetch operation, get the corresponding key, operate the getItem of the corresponding storage, and get the corresponding value from the corresponding storage.


console.log(storage.a); // 1

deleteProperty

Intercepts delete storage [propKey] operations and returns 1 Boolean value. What is intercepted here is the data deletion operation of the object, and the internal operation of storage is carried out to delete the data.


delete proxyStorageTest.a;

preventExtensions

Intercepts Object. preventExtensions (storage), returning a Boolean value. Intercept the non-extensible operation of the object, and internally perform clear operation on the corresponding storage to clear all stored values.


Object.preventExtensions(proxyStorageTest);

has

Intercepts the operation of propKey in proxy and the hasOwnProperty method of the object, returning 1 Boolean value. Intercept the operation of the query attribute of the object, and query whether a certain key exists in the corresponding storage.


'a' in proxyStorageTest;

Summarize

localStorage and sessionStorage are represented by Proxy, and a simple storage API is encapsulated. Proxy can be used to operate localStorage, sessionStorage, document, cookie, and indexedDB. Of course, the function of Proxy is not limited to this, and it also has many other uses, such as the use of Proxy in Vue 3.0, or others. The focus of this article is not to encapsulate a simple API, but to guide everyone to learn this idea.


Related articles: