第 103 题:模拟实现一个 localStorage

发布于 2022-11-14 15:33:41 字数 190 浏览 93 评论 35

localstorage 在浏览器的 API 有两个:localStorage 和sessionStorage,存在于 window 对象中:localStorage 对应 window.localStorage,sessionStorage 对应 window.sessionStorage。localStorage 和 sessionStorage 的区别主要是在于其生存期。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(35

笑叹一世浮▽沉 2022-05-04 13:55:32

难道不是应该用 cookie 模拟 localStorage 吗(兼容 IE8 及以下的 polyfill)?

!window.localStorage && !function(win) {
  var thousandYears = 1e3 * 365 * 24 * 36e5;

  function getCookies() {
    return document.cookie.match(/([^;=]+)=([^;]+)/g) || [];
  }

  function getExpires(flag) {
    flag = flag || 1;

    return 'expires=' +
      (new Date((+new Date()) + thousandYears * flag)).toUTCString();
  }

  function get(key) {
    var cookies = getCookies();

    for (var i = 0; i < cookies.length; i++) {
      var param = cookies[i].match(/^s*([^=]+)=(.+)/);

      if (param[1] === String(key)) {
        return decodeURIComponent(param[2]);
      }
    }

    return null;
  }

  function set(key, value, isExpired) {
    document.cookie = [
      key + '=' + encodeURIComponent(value),
      getExpires(isExpired ? -1 : 1),
      'path=/'
    ].join('; ');
  }

  function remove(key) {
    set(key, '', true);
  }

  function clear() {
    var cookies = getCookies();

    for (var i = 0; i < cookies.length; i++) {
      var key = cookies[i].match(/^s*([^=]+)/)[1];
      remove(key);
    }
  }

  // 注册到 window 对象上
  win.localStorage = {
    getItem: get,
    setItem: set,
    removeItem: remove,
    clear: clear
  };
}(window);

@wingmeng 使用cookie解决了刷新浏览器存储信息不被清除的问题,但是这样存储的信息就参与了服务器的通信,增加了请求负担,这个问题需要考虑吗

糖粟与秋泊 2022-05-04 13:55:32

@wingmeng 考虑了刷新浏览器存储信息不被清除。
是不是还得考虑 window.onstorage 的监听。

自此以后,行同陌路 2022-05-04 13:55:32
  1. same-origin rules 特定于页面的协议,还有隐身模式的区别
    当浏览器进入隐身模式(private browsing mode)的时候,会创建一个新的、临时的、空的数据库,用以存储本地数据(local storage data)。当浏览器关闭时,里面的所有数据都将被丢弃。

  2. 模拟持久存储
    a. like Internet Explorer < 8. It also makes use of cookies.
    b. IndexedDB
    c. WebSQL

  3. Storage Interface

interface Storage {
  readonly attribute unsigned long length;
  [IndexGetter] DOMString key(in unsigned long index);
  [NameGetter] DOMString getItem(in DOMString key);
  [NameSetter] void setItem(in DOMString key, in DOMString data);
  [NameDeleter] void removeItem(in DOMString key);
  void clear();
};
  1. localStorage 中的键值对总是以字符串的形式存储 key.toString() value.toString()
localStorage.setItem('a', {a:1})
undefined

localStorage.getItem('a')
"[object Object]"

a={a:1}
localStorage.setItem(a, {a:1})
{[object Object]: "[object Object]"}

localStorage.setItem('a', document.body)
localStorage.getItem('a')
"[object HTMLBodyElement]"
迷途知返 2022-05-04 13:55:32

// 模拟实现一个 localStorage
const localStorage = (function(){
let store = {};
return {
getItem(key){
return store[key] || null;
},
setItem(key,value){
store[key] = value.toString();
},
removeItem(key){
delete store[key]
},
clear(){
store = {};
}
}
})()

二智少女猫性小仙女 2022-05-04 13:55:32

` const localStorageMock = (function() {
let store = {}
return {
getItem: function(key) { return store[key] || null },
setItem: function(key, value) { store[key] = value.toString() },
removeItem: function(key) { delete store[key] },
clear: function() { store = {} },
}
})()

		Object.defineProperty(window, 'localStorage2', {
			value: localStorageMock
		})
		
		localStorage2.setItem('test', 'test')
		console.log(localStorage2.getItem("test"))  //test
		localStorage2.removeItem('test')
		console.log(localStorage2.getItem("test"))  //null
		localStorage2.setItem('test', 'test')
		localStorage2.clear()
		console.log(localStorage2.getItem("test"))  //null`

没有校验 value 是否为字符串

因为自带的localStorage也是把对象自动转成字符串的。我测试过自带的localStorage也是这样子。

楼主写的基本上跟浏览器自带的功能一样了,localStorage.setItem存一个对象时一般要加上JSON.stringify序列化下,localStorage.getItem取一个对象时再用JSON.parse反序列化下就可以了。

嘦怹 2022-05-04 13:55:32

localStorage 难道最主要的功能不是持久化存储么?还可以在控制台手动删除。上面的答案没有一个能打的啊

缱倦旧时光 2022-05-04 13:55:32

localStorage 难道最主要的功能不是持久化存储么?还可以在控制台手动删除。上面的答案没有一个能打的啊

你要知道,js的权限是被限制的,如果不用浏览器自带的,是不可能持久化的。

木森分化 2022-05-04 13:55:32

localStorage 难道最主要的功能不是持久化存储么?还可以在控制台手动删除。上面的答案没有一个能打的啊

你要知道,js的权限是被限制的,如果不用浏览器自带的,是不可能持久化的。

所以上面模拟的都是啥,就实现一个api也叫模拟么?就不说持久化存储好了,最基本的容量限制也没处理吧?

牵你手 2022-05-04 13:55:32

localStorage 难道最主要的功能不是持久化存储么?还可以在控制台手动删除。上面的答案没有一个能打的啊

你要知道,js的权限是被限制的,如果不用浏览器自带的,是不可能持久化的。

所以上面模拟的都是啥,就实现一个api也叫模拟么?就不说持久化存储好了,最基本的容量限制也没处理吧?

这,要不你设计一个,我们只是给自己的想法而已,有缺陷是很正常的啊。

陪你搞怪i 2022-05-04 13:55:32

使用Map数据结构构造localstorage

export class mockLocalstorage {
  constructor() {
    this.store = new Map(); // 记录存储数据
  }

  getItem(key) {
    const stringKey = String(key);
    if (this.store.has(stringKey)) {
      return String(this.store.get(stringKey));
    } else {
      return null;
    }
  }

  setItem(key, val) {
    try {
      this.store.set(String(key), val);
    } catch (e) {
      throw new Error(e);
    }
  }

  keys() {
    return Object.keys(this.store);
  }

  removeItem(key) {
    this.store.delete(String(key));
  }

  clear() {
    this.store.clear();
  }

  get length() {
    return this.store.size;
  }
}

测试

this.mockLocalstorage = new mockLocalstorage();
this.mockLocalstorage.setItem("name", "duya");
console.log(this.mockLocalstorage.getItem("name")); // 测试mockLocalstorage duya
鲜肉鲜肉永远不皱 2022-05-04 13:55:32
global.localStorage = new Proxy(instance, {
  set: function (obj, prop, value) {
    if (LocalStorage.prototype.hasOwnProperty(prop)) {
      instance[prop] = value
    } else {
      instance.setItem(prop, value)
    }
    return true
  },
  get: function (target, name) {
    if (LocalStorage.prototype.hasOwnProperty(name)) {
      return instance[name]
    }
    if (valuesMap.has(name)) {
      return instance.getItem(name)
    }
  }
})

为什么要用proxy啊,它的作用是什么呢?求解

忆沫 2022-05-04 13:55:32
'use strict'
const valuesMap = new Map()

class LocalStorage {
  getItem (key) {
    const stringKey = String(key)
    if (valuesMap.has(key)) {
      return String(valuesMap.get(stringKey))
    }
    return null
  }

  setItem (key, val) {
    valuesMap.set(String(key), String(val))
  }

  removeItem (key) {
    valuesMap.delete(key)
  }

  clear () {
    valuesMap.clear()
  }

  key (i) {
    if (arguments.length === 0) {
      throw new TypeError("Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.") // this is a TypeError implemented on Chrome, Firefox throws Not enough arguments to Storage.key.
    }
    var arr = Array.from(valuesMap.keys())
    return arr[i]
  }

  get length () {
    return valuesMap.size
  }
}
const instance = new LocalStorage()

global.localStorage = new Proxy(instance, {
  set: function (obj, prop, value) {
    if (LocalStorage.prototype.hasOwnProperty(prop)) {
      instance[prop] = value
    } else {
      instance.setItem(prop, value)
    }
    return true
  },
  get: function (target, name) {
    if (LocalStorage.prototype.hasOwnProperty(name)) {
      return instance[name]
    }
    if (valuesMap.has(name)) {
      return instance.getItem(name)
    }
  }
})

代理中这个判断又什么作用呀

localStorage 可以通过 localStorage.xxx 方式取值。

不用proxy,也可以localStorage.xxx方式取值啊~~~

南城追梦i 2022-05-04 13:55:32

localStorage 难道最主要的功能不是持久化存储么?还可以在控制台手动删除。上面的答案没有一个能打的啊

你要知道,js的权限是被限制的,如果不用浏览器自带的,是不可能持久化的。

所以上面模拟的都是啥,就实现一个api也叫模拟么?就不说持久化存储好了,最基本的容量限制也没处理吧?

这,要不你设计一个,我们只是给自己的想法而已,有缺陷是很正常的啊。

这个题目设计的没有意义。 我一看题目就觉得实现的是持久化存储

我不会写诗 2022-05-04 13:55:32

忽略了 localStorage 的特性,即刷新,关闭页面仍然存在。正解应该是使用能够持久化的方法或者接口,比如 cookie 来模拟实现。 #171

爱已欠费 2022-05-04 13:55:32

如题(localStorage)的核心功能没有体现,持久化存储不是js模拟能实现的,浏览器自带功能还是借助浏览器吧

仅此而已° 2022-05-04 13:55:32
'use strict'
const valuesMap = new Map()

class LocalStorage {
  getItem (key) {
    const stringKey = String(key)
    if (valuesMap.has(key)) {
      return String(valuesMap.get(stringKey))
    }
    return null
  }

  setItem (key, val) {
    valuesMap.set(String(key), String(val))
  }

  removeItem (key) {
    valuesMap.delete(key)
  }

  clear () {
    valuesMap.clear()
  }

  key (i) {
    if (arguments.length === 0) {
      throw new TypeError("Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.") // this is a TypeError implemented on Chrome, Firefox throws Not enough arguments to Storage.key.
    }
    var arr = Array.from(valuesMap.keys())
    return arr[i]
  }

  get length () {
    return valuesMap.size
  }
}
const instance = new LocalStorage()

global.localStorage = new Proxy(instance, {
  set: function (obj, prop, value) {
    if (LocalStorage.prototype.hasOwnProperty(prop)) {
      instance[prop] = value
    } else {
      instance.setItem(prop, value)
    }
    return true
  },
  get: function (target, name) {
    if (LocalStorage.prototype.hasOwnProperty(name)) {
      return instance[name]
    }
    if (valuesMap.has(name)) {
      return instance.getItem(name)
    }
  }
})

localStorage.key(i)访问key的时候,越界返回null,arr[i]越界返回undefined,需要修正这一点。

离不开的别离 2022-05-04 13:55:32

如果是要求实现localStorage的持久化存储功能....这是不可能的; 如果不是,那么这个题....好像没有什么意义啊,最多考察一下语法

巾帼英雄 2022-05-04 13:55:32

标注是阿里的题,明显考察的是用cookie实现polyfill,为啥一堆人认为在考api语法...

森林散布。 2022-05-04 13:55:32
		const localStorageMock = (function() {
			let store = {}
			return {
				getItem: function(key) { return store[key] || null },
				setItem: function(key, value) { store[key] = value.toString() },
				removeItem: function(key) { delete store[key] },
				clear: function() { store = {} },
			}
		})()

		Object.defineProperty(window, 'localStorage2', {
			value: localStorageMock
		})
		
		localStorage2.setItem('test', 'test')
		console.log(localStorage2.getItem("test"))  //test
		localStorage2.removeItem('test')
		console.log(localStorage2.getItem("test"))  //null
		localStorage2.setItem('test', 'test')
		localStorage2.clear()
		console.log(localStorage2.getItem("test"))  //null

可是这样无法实现持久存储啊

や三分注定━ 2022-05-04 13:55:32

全都没有考虑持久化存储呀, 我的想法是通过cookie或者indexedDB

雨落星ぅ辰 2022-05-04 13:55:32

使用indexedDB 模拟实现一个基础的 localStorage

index.html,添加一个触发按钮

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <button>set</button>
  </body>
</html>

<script src="./localStorageMock.js"></script>

localStorageMock.js

const name = Symbol('localStorageMock');
const localStorageMock = new (class {
  constructor() {
    Object.assign(this, { [name]: {}, db: {}, objectStore: {}, result: '' });
    Object.defineProperties(this, {
      DBOpenRequest: {
        value: window.indexedDB.open('localStorageMock', 1),
        writable: false,
        configurable: false,
      },
    });
    this.DBOpenRequest.onupgradeneeded = event => {
      this.db = event.target.result;
      if (!this.db.objectStoreNames.contains('store')) {
        this.objectStore = this.db.createObjectStore('store', { keyPath: 'name' });
        this.objectStore.createIndex('name', 'name', { unique: false });
      }
    };
    this.DBOpenRequest.onerror = event => console.error(event);
    this.DBOpenRequest.onsuccess = event => {
      this.db = event.target.result;
    };
  }
  /** 获取所有Storage数据列表 */
  readAll() {
    return new Promise(resolve => {
      let objectStore = this.db.transaction('store').objectStore('store');
      let arr = [];
      objectStore.openCursor().onsuccess = event => {
        let cursor = event.target.result;
        if (cursor) {
          arr.push(cursor.value);
          cursor.continue();
          return resolve(arr);
        } else {
          console.log('没有更多数据了!');
        }
      };
    });
  }
  getItem(key) {
    return new Promise((resolve, reject) => {
      let request = this.db
        .transaction(['store'], 'readonly')
        .objectStore('store')
        .index('name')
        .get(key);
      request.onerror = () => reject('事务失败');
      request.onsuccess = function(event) {
        if (request.result) {
          return resolve(request.result);
        } else {
          return reject('未获得数据记录');
        }
      };
    });
  }
  /** 注意隐患,刷新会情况this[name]数据,建议直接setItem */
  add(key, value) {
    console.log(this[name].hasOwnProperty(key));
    if (this[name].hasOwnProperty(key)) {
      return this.setItem(key, value);
    }
    Object.assign(this[name], { [key]: value });
    let request = this.db
      .transaction(['store'], 'readwrite')
      .objectStore('store')
      .add({ name: key, value: value });
    request.onsuccess = event => console.log('数据写入成功', event.target.result);
    request.onerror = err => console.error('数据写入失败', err.target.error);
  }
  removeItem(key) {
    let request = this.db
      .transaction(['store'], 'readwrite')
      .objectStore('store')
      .delete(key);
    request.onsuccess = () => console.log('数据删除成功');
    request.onerror = err => console.error('数据删除失败', err);
  }
  clear() {
    let request = this.db
      .transaction(['store'], 'readwrite')
      .objectStore('store')
      .clear();
    request.onsuccess = () => console.log('数据库清除成功');
    request.onerror = err => console.error('数据库清除失败', err);
  }
  setItem(key, value) {
    let request = this.db
      .transaction(['store'], 'readwrite')
      .objectStore('store')
      .put({ name: key, value: value });
    request.onsuccess = () => console.log('数据写入成功');
    request.onerror = err => console.error('数据写入失败', err);
  }
})();

document.getElementsByTagName('button')[0].addEventListener('click', async function() {
  console.log(localStorageMock);
  await localStorageMock.setItem('小明', '22岁');
  console.log(await localStorageMock.getItem('小明'));
  console.log(await localStorageMock.readAll());
  await localStorageMock.removeItem('小明');
  await localStorageMock.clear();
});
那小子欠揍 2022-05-04 13:55:29

https://html.spec.whatwg.org/multipage/webstorage.html

这个是localStorage的定义似乎还挺复杂的

世界如花海般美丽 2022-05-04 13:55:29

难道不是应该用 cookie 模拟 localStorage 吗(兼容 IE8 及以下的 polyfill)?

!window.localStorage && !function(win) {
  var thousandYears = 1e3 * 365 * 24 * 36e5;

  function getCookies() {
    return document.cookie.match(/([^;=]+)=([^;]+)/g) || [];
  }

  function getExpires(flag) {
    flag = flag || 1;

    return 'expires=' +
      (new Date((+new Date()) + thousandYears * flag)).toUTCString();
  }

  function get(key) {
    var cookies = getCookies();

    for (var i = 0; i < cookies.length; i++) {
      var param = cookies[i].match(/^s*([^=]+)=(.+)/);

      if (param[1] === String(key)) {
        return decodeURIComponent(param[2]);
      }
    }

    return null;
  }

  function set(key, value, isExpired) {
    document.cookie = [
      key + '=' + encodeURIComponent(value),
      getExpires(isExpired ? -1 : 1),
      'path=/'
    ].join('; ');
  }

  function remove(key) {
    set(key, '', true);
  }

  function clear() {
    var cookies = getCookies();

    for (var i = 0; i < cookies.length; i++) {
      var key = cookies[i].match(/^s*([^=]+)/)[1];
      remove(key);
    }
  }

  // 注册到 window 对象上
  win.localStorage = {
    getItem: get,
    setItem: set,
    removeItem: remove,
    clear: clear
  };
}(window);
℃柠檬色的※秋千 2022-05-04 13:55:28

如果我翻译的没错,红色下面应该说的是localStorage保存的数据理应都是字符串

岁月无声 2022-05-04 13:55:12
'use strict'
const valuesMap = new Map()

class LocalStorage {
  getItem (key) {
    const stringKey = String(key)
    if (valuesMap.has(key)) {
      return String(valuesMap.get(stringKey))
    }
    return null
  }

  setItem (key, val) {
    valuesMap.set(String(key), String(val))
  }

  removeItem (key) {
    valuesMap.delete(key)
  }

  clear () {
    valuesMap.clear()
  }

  key (i) {
    if (arguments.length === 0) {
      throw new TypeError("Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.") // this is a TypeError implemented on Chrome, Firefox throws Not enough arguments to Storage.key.
    }
    var arr = Array.from(valuesMap.keys())
    return arr[i]
  }

  get length () {
    return valuesMap.size
  }
}
const instance = new LocalStorage()

global.localStorage = new Proxy(instance, {
  set: function (obj, prop, value) {
    if (LocalStorage.prototype.hasOwnProperty(prop)) {
      instance[prop] = value
    } else {
      instance.setItem(prop, value)
    }
    return true
  },
  get: function (target, name) {
    if (LocalStorage.prototype.hasOwnProperty(name)) {
      return instance[name]
    }
    if (valuesMap.has(name)) {
      return instance.getItem(name)
    }
  }
})

代理中这个判断又什么作用呀

localStorage 可以通过 localStorage.xxx 方式取值。

鹤舞 2022-05-04 13:54:51

` const localStorageMock = (function() {
let store = {}
return {
getItem: function(key) { return store[key] || null },
setItem: function(key, value) { store[key] = value.toString() },
removeItem: function(key) { delete store[key] },
clear: function() { store = {} },
}
})()

		Object.defineProperty(window, 'localStorage2', {
			value: localStorageMock
		})
		
		localStorage2.setItem('test', 'test')
		console.log(localStorage2.getItem("test"))  //test
		localStorage2.removeItem('test')
		console.log(localStorage2.getItem("test"))  //null
		localStorage2.setItem('test', 'test')
		localStorage2.clear()
		console.log(localStorage2.getItem("test"))  //null`

没有校验 value 是否为字符串

因为自带的localStorage也是把对象自动转成字符串的。我测试过自带的localStorage也是这样子。

localStorage.setItem('test',{a:'a'})

我的也是这样的,你可以试一下啊。

沧桑㈠ 2022-05-04 13:54:09

` const localStorageMock = (function() {
let store = {}
return {
getItem: function(key) { return store[key] || null },
setItem: function(key, value) { store[key] = value.toString() },
removeItem: function(key) { delete store[key] },
clear: function() { store = {} },
}
})()

		Object.defineProperty(window, 'localStorage2', {
			value: localStorageMock
		})
		
		localStorage2.setItem('test', 'test')
		console.log(localStorage2.getItem("test"))  //test
		localStorage2.removeItem('test')
		console.log(localStorage2.getItem("test"))  //null
		localStorage2.setItem('test', 'test')
		localStorage2.clear()
		console.log(localStorage2.getItem("test"))  //null`

没有校验 value 是否为字符串

因为自带的localStorage也是把对象自动转成字符串的。我测试过自带的localStorage也是这样子。

localStorage.setItem('test',{a:'a'})

后知后觉 2022-05-04 13:54:01
'use strict'
const valuesMap = new Map()

class LocalStorage {
  getItem (key) {
    const stringKey = String(key)
    if (valuesMap.has(key)) {
      return String(valuesMap.get(stringKey))
    }
    return null
  }

  setItem (key, val) {
    valuesMap.set(String(key), String(val))
  }

  removeItem (key) {
    valuesMap.delete(key)
  }

  clear () {
    valuesMap.clear()
  }

  key (i) {
    if (arguments.length === 0) {
      throw new TypeError("Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.") // this is a TypeError implemented on Chrome, Firefox throws Not enough arguments to Storage.key.
    }
    var arr = Array.from(valuesMap.keys())
    return arr[i]
  }

  get length () {
    return valuesMap.size
  }
}
const instance = new LocalStorage()

global.localStorage = new Proxy(instance, {
  set: function (obj, prop, value) {
    if (LocalStorage.prototype.hasOwnProperty(prop)) {
      instance[prop] = value
    } else {
      instance.setItem(prop, value)
    }
    return true
  },
  get: function (target, name) {
    if (LocalStorage.prototype.hasOwnProperty(name)) {
      return instance[name]
    }
    if (valuesMap.has(name)) {
      return instance.getItem(name)
    }
  }
})

代理中这个判断又什么作用呀
localStorage不就这样么,你可以拿个浏览器看一下,这个比较细节了

温柔戏命师 2022-05-04 13:51:21
'use strict'
const valuesMap = new Map()

class LocalStorage {
  getItem (key) {
    const stringKey = String(key)
    if (valuesMap.has(key)) {
      return String(valuesMap.get(stringKey))
    }
    return null
  }

  setItem (key, val) {
    valuesMap.set(String(key), String(val))
  }

  removeItem (key) {
    valuesMap.delete(key)
  }

  clear () {
    valuesMap.clear()
  }

  key (i) {
    if (arguments.length === 0) {
      throw new TypeError("Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.") // this is a TypeError implemented on Chrome, Firefox throws Not enough arguments to Storage.key.
    }
    var arr = Array.from(valuesMap.keys())
    return arr[i]
  }

  get length () {
    return valuesMap.size
  }
}
const instance = new LocalStorage()

global.localStorage = new Proxy(instance, {
  set: function (obj, prop, value) {
    if (LocalStorage.prototype.hasOwnProperty(prop)) {
      instance[prop] = value
    } else {
      instance.setItem(prop, value)
    }
    return true
  },
  get: function (target, name) {
    if (LocalStorage.prototype.hasOwnProperty(name)) {
      return instance[name]
    }
    if (valuesMap.has(name)) {
      return instance.getItem(name)
    }
  }
})

代理中这个判断又什么作用呀

强辩 2022-05-04 13:50:19

这答案吓到我了。存储过之后,刷新页面,还能取出来吗???

且行且努力 2022-05-04 12:51:25
class mockLocalStorage {
  constructor() {
    this.store =  {}
  }
  getItem(key) {
    return this.store[key] || null
  }
  setItem(key,value) {
    this.store[key] = value
  }
  removeItem(key) {
    delete this.store[key]
  }
  clear() {
    this.store = {}
  }
}
window.localStorage2 = new mockLocalStorage()
梦毁影碎の 2022-05-03 18:11:33
'use strict'
const valuesMap = new Map()

class LocalStorage {
  getItem (key) {
    const stringKey = String(key)
    if (valuesMap.has(key)) {
      return String(valuesMap.get(stringKey))
    }
    return null
  }

  setItem (key, val) {
    valuesMap.set(String(key), String(val))
  }

  removeItem (key) {
    valuesMap.delete(key)
  }

  clear () {
    valuesMap.clear()
  }

  key (i) {
    if (arguments.length === 0) {
      throw new TypeError("Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.") // this is a TypeError implemented on Chrome, Firefox throws Not enough arguments to Storage.key.
    }
    var arr = Array.from(valuesMap.keys())
    return arr[i]
  }

  get length () {
    return valuesMap.size
  }
}
const instance = new LocalStorage()

global.localStorage = new Proxy(instance, {
  set: function (obj, prop, value) {
    if (LocalStorage.prototype.hasOwnProperty(prop)) {
      instance[prop] = value
    } else {
      instance.setItem(prop, value)
    }
    return true
  },
  get: function (target, name) {
    if (LocalStorage.prototype.hasOwnProperty(name)) {
      return instance[name]
    }
    if (valuesMap.has(name)) {
      return instance.getItem(name)
    }
  }
})
×眷恋的温暖 2022-05-03 14:01:28

` const localStorageMock = (function() {
let store = {}
return {
getItem: function(key) { return store[key] || null },
setItem: function(key, value) { store[key] = value.toString() },
removeItem: function(key) { delete store[key] },
clear: function() { store = {} },
}
})()

		Object.defineProperty(window, 'localStorage2', {
			value: localStorageMock
		})
		
		localStorage2.setItem('test', 'test')
		console.log(localStorage2.getItem("test"))  //test
		localStorage2.removeItem('test')
		console.log(localStorage2.getItem("test"))  //null
		localStorage2.setItem('test', 'test')
		localStorage2.clear()
		console.log(localStorage2.getItem("test"))  //null`

没有校验 value 是否为字符串

因为自带的localStorage也是把对象自动转成字符串的。我测试过自带的localStorage也是这样子。

ゞ香草可樂ゞ草莓布丁 2022-05-01 01:54:16

` const localStorageMock = (function() {
let store = {}
return {
getItem: function(key) { return store[key] || null },
setItem: function(key, value) { store[key] = value.toString() },
removeItem: function(key) { delete store[key] },
clear: function() { store = {} },
}
})()

		Object.defineProperty(window, 'localStorage2', {
			value: localStorageMock
		})
		
		localStorage2.setItem('test', 'test')
		console.log(localStorage2.getItem("test"))  //test
		localStorage2.removeItem('test')
		console.log(localStorage2.getItem("test"))  //null
		localStorage2.setItem('test', 'test')
		localStorage2.clear()
		console.log(localStorage2.getItem("test"))  //null`

没有校验 value 是否为字符串

装迷糊 2022-04-30 06:40:28
		const localStorageMock = (function() {
			let store = {}
			return {
				getItem: function(key) { return store[key] || null },
				setItem: function(key, value) { store[key] = value.toString() },
				removeItem: function(key) { delete store[key] },
				clear: function() { store = {} },
			}
		})()

		Object.defineProperty(window, 'localStorage2', {
			value: localStorageMock
		})
		
		localStorage2.setItem('test', 'test')
		console.log(localStorage2.getItem("test"))  //test
		localStorage2.removeItem('test')
		console.log(localStorage2.getItem("test"))  //null
		localStorage2.setItem('test', 'test')
		localStorage2.clear()
		console.log(localStorage2.getItem("test"))  //null
~没有更多了~

关于作者

梦在深巷

暂无简介

0 文章
0 评论
24 人气
更多

推荐作者

我早已燃尽

文章 0 评论 0

就像说晚安

文章 0 评论 0

donghfcn

文章 0 评论 0

凡尘雨

文章 0 评论 0

鲜血染红嫁衣

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文