How to Elegantly Rewrite localStorage and sessionStorage Methods
In front-end development, localStorage
and sessionStorage
are common tools for client-side data storage. However, certain business requirements—such as encryption, global monitoring, or preventing unauthorized access—may necessitate customizing their behavior. This article details how to rewrite these methods elegantly while retaining their native functionality.
Why Rewrite localStorage
and sessionStorage
?
Here are scenarios where rewriting can be beneficial:
- Business Customization: Add logic for specific keys, like encryption or validation.
- Global Monitoring: Track access logs and operation frequency.
- Data Protection: Safeguard critical keys from unauthorized modifications.
Core Approach
1. Retain Native Methods
Store references to the original methods:
1 const _setItem = localStorage.setItem;2 const _getItem = localStorage.getItem;
2. Proxy Methods
Rewrite the methods to include custom logic:
1 localStorage.setItem = function (key, value) {2 if (key === 'protectedKey') return; // Prevent modifications3 _setItem.call(this, key, value);4 };56 localStorage.getItem = function (key) {7 return key === 'protectedKey'8 ? 'Access denied'9 : _getItem.call(this, key);10 };
Flexible Configuration with Hooks
Introduce hooks for customization:
1 function proxyStorage(storage, config = {}) {2 const { beforeSetItem = (k, v) => [k, v], afterGetItem = (k, v) => v } = config;3 const _setItem = storage.setItem;4 const _getItem = storage.getItem;56 storage.setItem = function (key, value) {7 const [newKey, newValue] = beforeSetItem(key, value);8 _setItem.call(this, newKey, newValue);9 };1011 storage.getItem = function (key) {12 const value = _getItem.call(this, key);13 return afterGetItem(key, value);14 };15 }
Examples of Usage:
- Encrypt Data: Use a library like CryptoJS to encrypt and decrypt stored data.
- Log Operations: Record all setItem and getItem calls.
- Intercept Keys: Block access to specific keys.
Encapsulation with Singleton Class
Encapsulate the proxy logic in a singleton class for ease of use:
1 class StorageProxy {2 constructor(storage, config) {3 if (StorageProxy.instance) return StorageProxy.instance;4 this.init(storage, config);5 StorageProxy.instance = this;6 }78 init(storage, config) {9 this.storage = storage;10 this.originalSetItem = storage.setItem;11 this.originalGetItem = storage.getItem;12 this.config = config;1314 this.proxy();15 }1617 proxy() {18 const { storage, config: { beforeSetItem, afterGetItem } } = this;1920 storage.setItem = (key, value) => {21 const [k, v] = beforeSetItem(key, value);22 this.originalSetItem.call(storage, k, v);23 };2425 storage.getItem = (key) => {26 const value = this.originalGetItem.call(storage, key);27 return afterGetItem(key, value);28 };29 }3031 unproxy() {32 this.storage.setItem = this.originalSetItem;33 this.storage.getItem = this.originalGetItem;34 }35 }
Summary
Rewriting localStorage
and sessionStorage
allows for powerful business logic integration, enhanced security, and better data management. Encapsulate this functionality into reusable classes or modules to make your projects more maintainable and secure.