sisterAn / JavaScript-Algorithms

基础理论+JS框架应用+实践,从0到1构建整个前端算法体系

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

百度&阿里编程题:模拟实现一个 localStorage

sisterAn opened this issue · comments

可参考来源:
第 103 题:模拟实现一个 localStorage

一、localStorage 特性

1. Storage Interface

  • getItem(key)
  • setItem(key, value)
  • removeItem(key)
  • clear()
  • key(index)
  • length:readonly

2. 持久化存储
刷新、关闭页面依然存在

3. localStorage 中的键值对总是以字符串的形式存储 key.toString() value.toString()

localStorage.setItem('pzijun', 100)
localStorage.getItem('pzijun')
// "100"

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

var b = {}
localStorage.setItem(b, '11')
localStorage.getItem(b)
// "11"
localStorage.getItem(a)
// "11"

4. same-origin rules 特定于页面的协议,以及隐身模式等的区别

当浏览器进入隐身模式(private browsing mode)的时候,会创建一个新的、临时的、空的数据库,用以存储本地数据(local storage data)。当浏览器关闭时,里面的所有数据都将被丢弃。

二、用 cookie 模拟 localStorage

参考 https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie

window.LS = {
  getItem: function (sKey) {
    if (!sKey || !this.hasOwnProperty(sKey)) {
      return null;
    }
    return unescape(document.cookie.replace(new RegExp("(?:^|.*;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"), "$1"));
  },
  key: function (nKeyId) {
    return unescape(document.cookie.replace(/\s*\=(?:.(?!;))*$/, "").split(/\s*\=(?:[^;](?!;))*[^;]?;\s*/)[nKeyId]);
  },
  setItem: function (sKey, sValue) {
    if (!sKey) {
      return;
    }
    document.cookie = escape(sKey) + "=" + escape(sValue) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
    this.length = document.cookie.match(/\=/g).length;
  },
  length: 0,
  removeItem: function (sKey) {
    if (!sKey || !this.hasOwnProperty(sKey)) {
      return;
    }
    document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
    this.length--;
  },
  hasOwnProperty: function (sKey) {
    return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
  }
};
window.LS.length = (document.cookie.match(/\=/g) || window.LS).length;

if (!window.localStorage) {
  window.localStorage = window.LS;
}

测试:

LS.setItem('pzijun', 100)
LS.getItem('pzijun')
// "100"

var a = {
  a: 1
}
LS.setItem(a, {
  a: 1
})
LS.getItem(a)
// "[object Object]"

var b = {}
LS.setItem(b, '11')
LS.getItem(b)
// "11"
LS.getItem(a)
// "11"

另外还有容量控制、异常处理等,这里不再讨论,感兴趣的可以自己尝试实现下

三、扩展 localStorage 支持 expires 过期时间

(function () {
  var getItem = localStorage.getItem.bind(localStorage)
  var setItem = localStorage.setItem.bind(localStorage)
  var removeItem = localStorage.removeItem.bind(localStorage)
  localStorage.getItem = function (keyName) {
    var expires = getItem(keyName + '_expires')
    if (expires && new Date() > new Date(Number(expires))) {
      removeItem(keyName)
      removeItem(keyName + '_expires')
    }
    return getItem(keyName)
  }
  localStorage.setItem = function (keyName, keyValue, expires) {
    if (typeof expires !== 'undefined') {
      var expiresDate = new Date(expires).valueOf()
      setItem(keyName + '_expires', expiresDate)
    }
    return setItem(keyName, keyValue)
  }
})()

测试:

localStorage.setItem('key', 'value', new Date() + 10000) // 10 秒钟后过期
localStorage.getItem('key')
class LocalStorageFake {
  constructor() {
    this.storage = {};
  }

  getItem(key) {
    return this.storage[key];
  }

  setItem(key, value) {
    this.storage[key] = value;
  }
  removeItem(key) {
    delete this.storage[key];
  }
  clear() {
    this.storage = {};
  }
}