--- title: LocalStorage slug: conflicting/Web/API/Window/localStorage tags: - 存储API - 离线 translation_of: Web/API/Window/localStorage translation_of_original: Web/API/Web_Storage_API/Local_storage original_slug: Web/API/Storage/LocalStorage ---

localStorage 与 sessionStorage 一样,都遵循同源策略,但是它是持续存在的。localStorage 首次出现于 Firefox 3.5。

Note: 当浏览器进入隐私浏览模式,会创建一个新的、临时的数据库来存储local storage的数据;当关闭隐私浏览模式时,该数据库将被清空并丢弃。
// Save data to the current local store
localStorage.setItem("username", "John");

// Access some stored data
alert( "username = " + localStorage.getItem("username"));

本地存储(localStorage)的持续存在对许多事情都有帮助,包括这个示例this tutorial on Codepen所演示的记录页面查看次数。

兼容性

Storage 对象最近才加入标准,因此可能并不被所有浏览器支持。你可以通过在你的scripts代码前加入以下两段代码中某一段来规避在不能原生支持的执行环境使用localStorage对象的问题。

该算法借助于cookies,对localStorage对象进行了严谨的实现。

if (!window.localStorage) {
  Object.defineProperty(window, "localStorage", new (function () {
    var aKeys = [], oStorage = {};
    Object.defineProperty(oStorage, "getItem", {
      value: function (sKey) { return sKey ? this[sKey] : null; },
      writable: false,
      configurable: false,
      enumerable: false
    });
    Object.defineProperty(oStorage, "key", {
      value: function (nKeyId) { return aKeys[nKeyId]; },
      writable: false,
      configurable: false,
      enumerable: false
    });
    Object.defineProperty(oStorage, "setItem", {
      value: function (sKey, sValue) {
        if(!sKey) { return; }
        document.cookie = escape(sKey) + "=" + escape(sValue) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
      },
      writable: false,
      configurable: false,
      enumerable: false
    });
    Object.defineProperty(oStorage, "length", {
      get: function () { return aKeys.length; },
      configurable: false,
      enumerable: false
    });
    Object.defineProperty(oStorage, "removeItem", {
      value: function (sKey) {
        if(!sKey) { return; }
        document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
      },
      writable: false,
      configurable: false,
      enumerable: false
    });
    this.get = function () {
      var iThisIndx;
      for (var sKey in oStorage) {
        iThisIndx = aKeys.indexOf(sKey);
        if (iThisIndx === -1) { oStorage.setItem(sKey, oStorage[sKey]); }
        else { aKeys.splice(iThisIndx, 1); }
        delete oStorage[sKey];
      }
      for (aKeys; aKeys.length > 0; aKeys.splice(0, 1)) { oStorage.removeItem(aKeys[0]); }
      for (var aCouple, iKey, nIdx = 0, aCouples = document.cookie.split(/\s*;\s*/); nIdx < aCouples.length; nIdx++) {
        aCouple = aCouples[nIdx].split(/\s*=\s*/);
        if (aCouple.length > 1) {
          oStorage[iKey = unescape(aCouple[0])] = unescape(aCouple[1]);
          aKeys.push(iKey);
        }
      }
      return oStorage;
    };
    this.configurable = false;
    this.enumerable = true;
  })());
}
注意:数据的最大大小是通过cookies来严格限制的。可以使用这样的算法实现,使用localStorage.setItem()localStorage.removeItem()这两个函数进行添加、改变或删除一个键。使用方法为localStorage.yourKey = yourValue;和delete localStorage.yourKey;进行设置和删除一个键并不是安全的做法。您也可以改变它的名字和使用它仅仅去管理文档的cookies而不管localStorage 这个对象。
注意:通过将字符串"; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/" 改成"; path=/"(并且改变对象的名字),可以使得这个 localStorage的实现变为sessionStorage的实现。然而,这种实现方式会使储存键值可以跨标签和窗口访问(而且只会在浏览器窗口被关闭时销毁),完全兼容的sessionStorage实现会将储存键值访问权限限定在当前浏览上下文。

下面是另一个,并不那么严谨的localStorage对象的实现。相比上一个方法,它更简单且能与旧的浏览器良好兼容,如Internet Explorer < 8 (甚至能在 Internet Explorer 6 上正常工作)。它同样是使用cookies来实现的。

if (!window.localStorage) {
  window.localStorage = {
    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.localStorage.length = (document.cookie.match(/\=/g) || window.localStorage).length;
}
注意:数据量的最大值是通过cookies来严格限制的。可以使用localStorage.getItem()localStorage.setItem()localStorage.removeItem()等方法获取、设置或删除一个键。使用方法localStorage.yourKey = yourValue;获取、添加、改变或者删除一个键并不是安全的做法。您也可以改变它的名字和使用它仅仅去管理文档的cookies而不管localStorage 这个对象。
注意:通过将字符串"; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/" 改成"; path=/"(并且改变对象的名字),可以使得这个 localStorage的实现变为sessionStorage的实现。然而,这种实现方式会使储存键值可以跨标签和窗口访问(而且只会在浏览器窗口被关闭时销毁),完全兼容的sessionStorage实现会将储存键值限定在当前浏览环境上下文。

与globalStorage的兼容性及关系

localStorage 和 globalStorage[location.hostname] 是一样的, 除了作用域是在 HTML5 origin (结构 + 主机名 + 非标准的端口), 并且 localStorage 是一个 Storage 实例 ,而globalStorage[location.hostname] 是一个 StorageObsolete 实例,下面将要讨论这个。 例如, http://example.com 无法访问与 https://example.com 相同的 localStorage 对象 ,但是它们可以访问同一个 globalStoragelocalStorage 是标准的接口,globalStorage 不是, 所以不要依赖于 globalStorage 。   

请注意,给globalStorage[location.hostname]设置一个属性并不会影响到localStorage。拓展Storage.prototype也不会影响globalStorage对象,只有拓展StorageObsolete.prototype才会影响。

存储格式

Storage的键和值都是以每个字符占2个字节的UTF-16字符串(DOMString)格式存储的。