8

如何重写 localStorage 中的方法

 2 years ago
source link: https://www.xiabingbao.com/post/javascript/rewrite-localstorage-rcw995.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
经常会想要重写 localStorage 来实现某个功能,都有哪些方法重写 localStorage 里的方法呢?

经常会有同学想要重写 localStorage 中的方法,来实现 key 的过期时间,或者监听 key 的读写等。那么都有哪些方法重写 localStorage 里的方法呢?

1. 直接在 localStorage 上重写

很多同学喜欢重写的思路,先留存原生的方法,然后直接在 localStorage 上重写该方法,如:

const { setItem } = localStorage;

localStorage.setItem = function (key, value) {
  console.log('localStorage.setItem', key, value);
  setItem.call(this, key, value);
};

不过这种写法,并不是重写setItem()方法,而是在 localStorage 上添加了一个 setItem 的属性,该属性的值就是后面声明的方法,然后把原生的 setItem() 方法给覆盖掉了。

具体我没有太测试,不过在有的浏览器里,会忽略该属性,导致我们的重写失效。

2. 重写 localStorage.__proto__ 上的方法

我们仔细观察的话,setItem、getItem 都是以 __proto__ 的方式继承自 Storage 的。

localStorage的__proto__-蚊子的前端博客

那我们直接重写 localStorage.__proto__ 上面的方法。

const { setItem } = localStorage.__proto__;

localStorage.setItem = function (key, value) {
  console.log('localStorage.__proto__.setItem', key, value);
  setItem.call(this, key, value);
};

这就实现了 setItem()方法真正的重写。

但这里还有个问题,localStorage 和 sessionStorage 都是继承自Storage,重写了 localStorage.__proto__ 上的属性或方法后,也把 sessionStorage 里的方法重写了。

把sessionStorage里的方法也重写了-蚊子的前端博客

3. 外部封装一层

我们不直接对 localStorage 本身的方法进行修改,而是在外面包装一层,底层再使用 localStorage 实现存储功能。

class MyLocalStorage {
  setItem(key, value) {
    console.log('MyLocalStorage.setItem', key, value);
    localStorage.setItem(key, value);
  }
}

const myLocalStorage = new MyLocalStorage();
myLocalStorage.setItem('aa', '123');

这种方式相对来说,自由度会高一些,而且也没有第 1 节中的兼容性问题。只是使用的名称发生了变化,而且还完全把 localStorage 里的属性和方法都屏蔽掉了。

若想没有负担地使用自定义的对象,则需要把所有的属性和方法都实现了。无法像上面那种,单独 mock 某个方法。

4. 覆盖 localStorage

使用Object.definePropertyProxy等方式,完全覆盖掉 localStorage 变量。比第 3 节好的地方在于名称没变。

4.1 直接覆盖,没有效果

若使用下面的方式直接覆盖的话,其实是没有效果的。

window.localStorage = Object.create(null);

console.log(window.localStorage); // 还是原生的

我们通过 Object.getOwnPropertyDescriptor 获取 localStorage 的属性描述符。可以发现并没有writable: true的属性,这说明 localStorage 并不是直接可写的。

localStorage的getOwnPropertyDescriptor-蚊子的前端博客

4.2 使用 Object.defineProperty 重写

既然没有writable属性,那我们就给他加一个。我们可以用Object.defineProperty来重写 localStorage。

但就不能用上面外面包一层的写法了,若直接将上面的 myLocalStorage 给到 localStorage 的话,会产生无限递归(为避免生成误导,这里就不写错误的写法了)。

((win) => {
  const nativeLocalStorage = win.localStorage;
  win.nativeLocalStorage = nativeLocalStorage; // 保留原生的使用

  class MyLocalStorage {
    setItem(key, value) {
      console.log('MyLocalStorage.setItem', key, value);
      nativeLocalStorage.setItem(key, value);
    }

    getItem(key) {
      console.log('MyLocalStorage.getItem', key);
      return nativeLocalStorage.getItem(key);
    }
  }

  const myLocalStorage = new MyLocalStorage();
  // 将新创建的实例赋值给localStorage
  Object.defineProperty(win, 'localStorage', {
    value: myLocalStorage,
    writable: true,
  });
})(window);

我这里对 localStoage 进行了下备份,万一要需要原生的方法时,还可以操作一下。

这篇文章里,我们并没有具体地实现某个功能,如设置过期时间等,而是从另一个角度讲了下如何重写 localStorage 或者里面的方法。


Recommend

  • 128
    • zhuanlan.51cto.com 7 years ago
    • Cache

    Java中方法的重写与成员变量的隐藏

    Java中方法的重写与成员变量的隐藏-51CTO.COM Java中方法的重写与成员变量的隐藏 作者:Hollis 2017-09-30 09:10:21 这篇文章讨论了Java面向对象概念中一个基本的概念–Field Hiding(隐...

  • 22
    • developer.51cto.com 5 years ago
    • Cache

    如何重写object虚方法

    【51CTO.com原创稿件】 在 C# 中 Object 是所有类的基类,所有的结构和类都直接或间接的派生自它。前面这段话可以说所有的 C# 开发人员...

  • 8
    • bboyjing.github.io 4 years ago
    • Cache

    Java中方法与字段的重写

      本章我们来看一下,Java中字段和方法是如何参与重写的。 字段的重写  首先,需要明确一点,Java的字段永远不参与多态,当子类声明了与父类同名的字段时,虽然在子类的内存中两个字段都会存在,但是子类的字段会屏蔽父类的同名字段。我们来看...

  • 6
    • www.xiabingbao.com 3 years ago
    • Cache

    如何判断一个原生方法是否被重写

    如何判断一个原生方法是否被重写 蚊子前端博客 发布于 2020-11-12 11:44 有的脚本会重写该方法,那么如何判断这个方法是否被重写了呢? 浏览器根据 ECMScript 标...

  • 8

    V2EX  ›  JavaScript [IT 邦帮忙] 优化或重写方法,使计算长字符串时尽可能缩短运算时间   ciddechan

  • 7
    • kemchenj.github.io 3 years ago
    • Cache

    或许你并不需要重写 init(from:) 方法

    Codable 作为 Swift 的特性之一也是很注重安全,也很严谨,但它对于“严谨”和“安全”的定义不一定跟别的语言一样,这就导致了它在实际使用时总会有这样那样的磕磕绊绊,我们不得不重写 init 方法去让它跟外部环境融洽地共存。最近在工作中这样的事情发生多了,我...

  • 5
    • segmentfault.com 3 years ago
    • Cache

    重写数组的方法(改变原数组)

    下图是我自我学习模拟数组时总结的一些重新数组的方法:本文我们暂不讨论不改变原数组的方法,只谈改变原数组用到的 6 种方法。改变原数组的方法push()按参数顺序向数组尾部添加元素,返回新数组的长度

  • 5

    Django model重写save方法及update踩坑记录 一个非常实用的小方法 试想一下,Django中如果我们想对保存进数据库的数据做校验,有哪些实现的方法? 我们可以在view中去处理,每当view接收请求,就对...

  • 5

    重写并自定义依赖的原生的Bean方法 转载请注明出处:

  • 4
    • droidyue.com 2 years ago
    • Cache

    Vs Code 快速实现 重写 方法

    Vs Code 快速实现 重写 方法 Feb 12th, 2023 作为一个从 Android Studio/IntelliJ 切到 VS code 的开发者,一开始会遇到各种不...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK