您的位置:首页 > 其它

客户端存储

2013-12-14 16:09 113 查看
Web应用允许使用浏览器提供的API实现将数据存储到用户的电脑上。这种客户端存储相当于赋予了Web浏览器记忆功能。比方说,Web应用就可以用这种方式来“记住”用户的配置信息甚至是用户所有的状态信息,以便准确地“回忆”起用户上一次访问时候的状态。客户端存储遵循“同源策略”,因此不同站点的页面是无法互相读取对方存储数据的,而同一站点的不同页面之间是可以互相共享存储数据的,它为我们提供了一种通信机制,例如,一个页面上填写的表单数据可以显示在另外一个页面中。Web应用可以选择它们存储数据的有效期:比如采用临时存储可以让数据保存至当前窗口关闭或者浏览器退出;采用永久存储,可以将数据永久地存储到硬盘上,永不失效。

客户端存储有以下几种形式:

Web存储

Web存储最初作为HTML5一部分被定义成API形式,但是后来被剥离出来作为独立的一份标准了。该标准目前还在草案阶段,但其中一部分内容已经被包括IE8在内的所有主流浏览器实现了。Web存储标准所描述的API包含了 localStorage 对象和 sessionStorage 对象,这两个对象实际上是持久化关联数组,是名值对的映射表,“名”和“值”都是字符串。Web存储易于使用、支持大容量(但非无限量)数据存储同时兼容当前所有主流浏览器,但是不兼容早期浏览器。§20.1 会对 localStorage
和 sessionStorage 这两个对象作详细介绍。

Cookies

Cookie是一种早期的客户端存储机制,起初是针对服务器端脚本设计使用的。尽管在客户端提供了非常繁琐的JavaScript API来操作Cookie,但却难用之极,而且只能存储少量文本数据。不仅如此,任何以Cookie形式存储的数据,不论服务器端是否需要,每一次HTTP请求都会把这些数据传输到服务器端。Cookie目前仍然被客户端开发者大量使用的一个重要原因是:所有浏览器都支持它。但是,随着Web Storage的普及,Cookie终将会回归到最初的形态:作为一种被服务端脚本使用的客户端存储机制。§20.2会详细介绍Cookie。

 

离线Web应用

HTML5标准中定义了一组“离线Web应用”API,用以缓存web页面以及相关资源(脚本、CSS文件、图片等等)。它实现的是将web应用整体存储在客户端,而不仅仅是存储数据。它能够让web应用“安装”在客户端,这样一来,哪怕网络不可用的时候web应用依然是可用的。离线web应用相关的内容会在§20.4中作介绍。

 

20.1 localStorage 和 sessionStorage

实现了”Web存储“草案标准的浏览器在window对象上定义了两个属性:localStorage和sessionStorage。这两个属性都代表同一个Storage对象——一个持久化关联数组,数组使用字符串来索引,存储的值也都是字符串形式的。Storage对象在使用上和一般的JavaScript对象没什么区别:设置对象的属性为字符串值,随后浏览器会将该值存储起来。localStorage和sessionStorage两者的区别在于存储的有效期和作用域的不同:数据可以存储多长时间以及谁拥有数据的访问权。

下面,我们会对存储的有效期和作用域作详细的解释。不过,在此之前,让我们先来看些例子。下面的代码使用的是localStorage,但是它对sessionStorage也同样适用:

var name = localStorage.username; // 查询一个存储的值。
name = localStorage["username"]; // 等价于数组表示法
if (!name) {
name = prompt("What is your name?"); // 询问用户一个问题。
localStorage.username = name; // 存储用户的答案。
}

// 迭代所有存储的name/value对
for(var name in localStorage) { // 迭代所有存储的名字
var value = localStorage[name]; // 查询每个名字对应的值
}

Storage对象还定义了一些诸如存储、获取、遍历和删除的方法。这些方法会在§20.1.2中作介绍。

”Web存储”草案标准指出,我们既可以存储结构化的数据(对象和数组),也可以存储原始类型数据,还可以存储诸如日期、正则表达式甚至文件对象在内的内置类型的数据。但是,截止至本书截稿时,浏览器仅仅支持存储字符串类型数据。如果想要存储和获取其他类型的数据,不得不自己手动进行编码和解码。如下例子所示:

// 当存储一个数字的时候,它会被自动转换成字符串。
// 但是,当获取该值的时候别忘记了手动将其转换成数字类型。
localStorage.x = 10;
var x = parseInt(localStorage.x);

// 同样地,存储一个日期类型数据的时候进行编码,获取的时候进行解码
localStorage.lastRead = (new Date()).toUTCString();
var lastRead = new Date(Date.parse(localStorage.lastRead));

// 使用JSON可以使得对基本数据类型编码的工作变得很方便
localStorage.data = JSON.stringify(data); // 编码然后存储。
var data = JSON.parse(localStorage.data); // 获取数值之后再解码。

20.1.1 存储有效期和作用域

localStorage和sessionStorage的区别在于存储的有效期和作用域的不同。通过localStorage存储的数据是永久性的,除非web应用刻意删除存储的数据,或者用户通过设置浏览器配置(浏览器提供的配置界面)来删除,否则数据将一直保留在用户的电脑上,永不过期。

localStorage的作用域是限定在文档源(document origin)级别的。正如§13.6.2所介绍的,文档源是通过协议、主机名以及端口三者来确定的,因此,下面每个URL都拥有不同的文档源:

http://www.example.com              // 协议: http; 主机名: www.example.com https://www.example.com            // 不同协议 http://static.example.com              // 不同主机名 http://www.example.com:8000      // 不同端口

同源的文档间共享同样的localStorage数据(不论该源的脚本是否真正地操作localStorage)。它们可以互相读取对方的数据,甚至可以覆盖对方的数据。但是,非同源的文档间互相都不能读写对方数据(即使它们运行的脚本是来自同一台第三方服务器也不行)。

需要注意的是localStorage的作用域也受浏览器供应商限制。如果你使用Firefox访问站点,那么下次用另一个浏览器比方说是Chrome再次访问的时候,那么本次是无法获取上次存储的数据的。

通过sessionStorage存储的数据和通过localStorage存储的数据的有效期也是不同的:前者有效期和存储数据的脚本所在的最顶层的窗口或者是浏览器标签页是一样的。一旦窗口或者标签页被永久关闭了,那么所有通过sessionStorage存储的数据也都被删除了。(当时要注意的是,现代浏览器已经具备了重新打开最近关闭的标签页随后恢复上一次浏览的session功能,因此,这些标签页以及与之相关的sessionStorage的有效期可能会更加长些)。

与localStorage一样,sessionStorage的作用域也是限定在文档源中,因此非同源文档间都是无法共享sessionStorage的。不仅如此,sessionStorage 的作用域还被限定在窗口中。如果同源的文档渲染在不同的浏览器标签页中,那么他们互相之间拥有的是各自的sessionStorage数据,无法共享;一个标签页中的脚本是无法读取或者覆盖由另一个标签页脚本写入的数据,哪怕这两个标签页渲染的是同一个页面,运行的是同一个脚本也不行。

要注意的是:这里提到的基于窗口作用域的sessionStorage指的窗口只是顶级窗口。如果一个浏览器标签页包含两个
<iframe>
元素,他们所包含的文档是同源的,那么这两者之间是可以共享sessionStorage的。

20.1.2 存储API

localStorage和sessionStorage通常被当做普通的JavaScript对象使用:通过设置属性来存储字符串值,查询该属性来读取该值。除此之外,这两个对象还提供了更加正式的API。调用setItem()方法,将对应的名字和值传递进去,可以实现数据存储。调用getItem()方法,将名字传递进去,可以获取对应的值。调用removeItem()方法,将名字传递进去,可以删除对应的数据。(在非IE8浏览器中,还可以使用delete操作符来删除数据,就和对普通的对象使用delete操作符一样。)调用clear()方法(不需要参数),可以删除所有存储的数据。最后,使用length属性以及key()方法,传入0到length-1的数字,可以枚举所有存储数据的名字。下面是一些使用localStrage的例子。这些代码对sessionStorage也适用:

localStorage.setItem("x", 1);   // 以“x”的名字存储一个数值
localStorage.getItem("x");   // 获取数值

// 枚举所有存储的名字/值对
for(var i = 0; i < localStorage.length; i++) { // length表示了所有名字/值对的总数
var name = localStorage.key(i); // 获取第i对的名字
var value = localStorage.getItem(name); // 获取该对的值
}

localStorage.removeItem("x"); // 删除“x”项
localStorage.clear(); // 全部删除

尽管通过设置和查询属性能更加方便的存储和获取数据,但是有的时候还是不得不使用上面提到的这些方法的。比方说,其中clear()方法是唯一能删除存储对象中所有名/值对的方式。同样的还有,removeItem()方法也是唯一通用的删除单个名/值对的方式,因为IE8不支持delete操作符。

如果浏览器提供商完全实现了“Web存储”的标准,支持对象和数组类型的数据存储,那么就会又多了一个使用类似于setItem()和getItem()这类方法的理由了。对象和数组类型的值通常是可变的,因此存储对象要求存储他们的副本,以确保之后任何对这类对象的改变都不影响到存储的对象。同样的,在获取该对象的时候也要求获取的是该对象的副本,以确保对已获取对象的改动不会影响到存储的对象。而这类操作如果使用基于属性的API就会令人困惑。考虑下面这段代码(假设浏览器已经支持了结构化数据的存储):

localStorage.o = {x:1}; // 存储一个带有“x”属性的对象
localStorage.o.x = 2; // 试图去设置该对象的属性值
localStorage.o.x // => 1: x没有变

上述第二行代码想要设置存储的对象的属性值,但是事实上,它获取到的只是存储的对象的拷贝,随后设置了该对象的属性值,然后就将该拷贝的对象废弃了。真正存储的对象保持不变。像这样的情况,使用getItem()就不会这么让人困惑了。

localStorage.getItem("o").x = 2; // 我们并不想存储2

PI的理由就是:在还不支持“Web存储”标准的浏览器中,其他的存储机制的顶层API对其也是兼容的。下面这段代码使用cookies和IE userDate来实现存储API、如果使用基于方法的API,当localStorage可用的时候就可以使用它编写代码,而当它在其他浏览器上不可用的时候依然可以降级到其他的存储机制中(译者注:完全兼容)。代码如下所示:

// 识别出使用的是哪类存储机制
var memory = window.localStorage ||
(window.UserDataStorage && new UserDataStorage()) ||
new CookieStorage();
// 然后在对应的机制中查询数据
var username = memory.getItem("username");

20.1.3 存储事件

无论什么时候存储在localStorage或者sessionStorage的数据发生改变,浏览器都会对其他对该数据可见的窗口对象上触发存储事件(但是,在对数据进行改变的窗口对象上是不会触发的)。如果浏览器有两个标签页都打开了来自同源的页面,其中一个页面在localStorage上存储了数据,那么另外一个标签页就会接收到一个存储事件。要记住的是sessionStorage作用域是限制在顶层窗口的,因此对sessionStorage的改变只有当有相牵连的窗口的时候才会触发存储事件。还有要注意的是,只有当存储数据真正发生改变的时候才会触发存储事件。像给已经存在的存储项设置一个一模一样的值,抑或是删除一个本来就不存在的存储项都是不会触发存储事件的。

为存储事件注册处理程序可以通过addEventListener()方法(或者在IE下使用attachEvent()方法)。在绝大多数浏览器中,还可以使用给window对象设置onstorage属性的方式,不过Firefox不支持该属性。

与存储事件相关的事件对象有五个非常重要的属性(遗憾的是,IE8不支持它们):

key

被设置或者移除的项的名字或者键名。如果调用的是clear()函数,那么该属性值为null。

newValue

该项的新的值;或者调用removeItem()时,该属性值为null。

oldValue

被改变或者删除前,该项原先的值;当插入一个新项的时候,该属性值为null。

storageArea

这个属性值就好比是目标window对象上的localStorage属性或者是sessionStorage属性

url

触发该存储变化脚本所在文档的URL

最后要注意的是:localStorage和存储事件都是采用广播机制的,浏览器会对目前正在访问同样站点的所有窗口发送消息。举个例子,比方说一个用户要求网站停止动画效果,那么站点可能会在localStorage中存储该用户的配置,这样依赖,以后再访问该站点的时候就自动停止动画效果了。因为存储了该配置,导致了触发一个存储事件让其他展现统一站点的窗口也获得了这样的一个用户请求。再比如,一个基于web的图片编辑应用,通常允许在其他的窗口中展示工具条。当用户选择一个工具的时候,应用就可以使用localStorage来存储当前的状态,然后通知其他窗口用户选择了新的工具。

 

 

20.2 Cookies

cookie是指浏览器存储的少量数据,同时它是与具体的web页面或者站点相关的。Cookie最早是设计为被服务端所用的,从最底层来看,它被实现为是HTTP协议的一种扩展。cookie数据会被自动在web浏览器和web服务器之间传输的,因此服务端脚本就可以读写存储在客户端的cookie的值。本节内容将介绍客户端的脚本通过使用Document对象上的cookie属性也能实现对cookie的操作。

为什么叫“Cookie?”
“cookie”这个名字没有太多的含义,但是在计算机历史上其实很早就有用到它了。“cookie”和“magic cookie”用于代表少量数据,特别是指类似密码这种用于识别身份或者许可访问的保密数据。在JavaScript中,cookie被用于保存状态以及能够为web浏览器提供一种身份识别机制。但是,JavaScript中使用cookie不会采用任何加密机制,因此他们是不安全的。(但是,通过https来传输cookie数据是安全的,不过这和cookie本身无关,而和https协议相关。)

操作cookie的API很早就已经定义和实现了,因此该API的兼容性很好。但是,该API几乎形同虚设。根本没有提供诸如查询、设置、删除cookie的方法,所有这些操作都要通过以特殊格式的字符串形式读写Document对象的cookie属性来完成。每个cookie的有效期和作用域都可以通过cookie属性来指定。这些属性也是通过在同一个cookie属性上以特殊格式的字符串来设定的。

本节剩余部分会解释如何通过cookie属性来指定cookie的有效期和作用域,以及如何通过JavaScript来设置和查询cookie的值。最后,将以一个“实现基于cookie的存储API”例子来结束本节的介绍。

检测cookie是否启用
由于滥用第三方cookie(译注:第三方cookie指的是来自于当前访问站点以为的站点设置的cookie)(如:cookie是和网页上的图片相关而非网页本身相关)的缘故,导致cookie在大多数web用户心目中都留下了很不好的印象。比如,广告公司可以利用第三方cookie来实现跟踪用户的访问行为和习惯,而用户为了禁止这种”窥探“用户隐私的行为会在他们的浏览器中禁用cookie。因此,在使用cookie前,首先要确保cookie是启用的。在绝大多数浏览器中,可以通过检测navigator.cookieEnabled这一属性。若该值为true,则当前cookie是启用的,反之则是被禁用的(但是,只具备”当前浏览会话生命周期“的非持久化cookie仍然是启用的)。但是,该属性不是一个标准的属性(不是所有浏览器都支持的)。因此在不支持该属性的浏览器上,必须通过使用下面将要介绍的技术尝试着读、写和删除测试cookie数据来测试是否支持cookie。

20.2.1 Cookie属性:有效期和作用域

除了名(name)和值(value),cookie还有一些可选的属性来控制cookie的有效期和作用域。cookie默认的有效期很短暂;它只能持续在web浏览器的会话期间,一旦用户关闭浏览器cookie,保存的数据就丢失了。要注意的是:这与sessionStorage的有效期还是有区别的:coookie的作用域并不是局限在单个的浏览器窗口中,它的有效期和整个浏览器进程而不是单个浏览器窗口的有效期一致。如果想要延长cookie的有效期,可以通过设置max-age属性,但是必须要明确告诉浏览器cookie的有效期是多长(单位是秒)。一旦设置了有效期,浏览器就会将cookie数据存储在一个文件中,并且直到过了指定的有效期才会删除该文件。

和localStorage以及sesstionStorage类似,cookie的作用域是通过文档源和文档路径来确定的。该作用域通过cookie的path和domain属性也是可配置的。默认情况下,cookie和创建它的页面有关,并对该页面以及和该页面同目录或者子目录的其他页面可见。比如,Web页面http://www.example.com/catalog/index.html页面创建了一个cookie,那么该cookie对http://www.example.com/catalog/order
.html页面和http://www.example.com/catalog/widgets/index.html页面都是可见的,但它对http://www.example.com/about.html页面不可见。

默认的cookie的可见性行为满足了最常见的需求。不过,有的时候,你可能希望让整个网站都能够使用cookie的值,而不管是哪个页面创建它的。比方说,当用户在一个页面表单中输入了他的邮件地址,你想将它保存下来,为了下次该用户回到这个页面填写表单,或者网站其他页面任何地方要求输入账单地址的时候,将其作为默认的邮件地址。要满足这样的需求,可以通过设置cookie的路径(设置cookie的path属性)。

这样一来,来自同一服务器的Web页面,只要其URL是以指定的路径前缀开始的,都可以共享cookie。举例来说,如果http://www.example.com/catalog/widgets/index.html 页面创建了一个cookie,并且将该路径设置成“/catalog”,那么该cookie对于http://www.example.com/catalog/order.html 页面也是可见的。或者,如果把路径设置成“/”,那么该cookie对任何http://www.example.com
这台Web服务器上的页面都是可见的。

将cookie的路径设置成“/”等于是让cookie和localStorage拥有同样的作用域,同时请求该站点上任何一个页面的时候,浏览器都必须将cookie的名字和值传递给服务器。但是,要注意的是,cookie的path属性不能被用作访问控制机制。如果一个Web页面想要读取同一站点其他页面的cookie,只要简单的将其他页面以隐藏
<iframe>
的形式嵌入进来,随后读取对应文档的cookie就可以了。同源策略(§13.6.2)限制了跨站的cookie窥探,但是对于同一站点的文档它是完全合法的。

cookie的作用域默认是被文档源限制。但是,有的大型网站想要子域之间能够互相共享cookie。比方说,order.example.com域下的页面想要读取catalog.example.com域下设置的cookie。这个时候就需要通过设置cookie的domain属性来达到目的了。如果一个catalog.example.com域下的页面创建了一个cookie,并将其path属性设置成“/”,其domain属性设置成“.example.com”,那该cookie就对所有catalog.example.com、orders.example.com以及任何其他example.com域下的页面可见了。如果没有为一个cookie设置域属性,那么domain属性的默认值是当前Web服务器的主机名。要注意的是,cookie的域只能设置为当前服务器的域。

最后要介绍的cookie的属性是secure,它是一个布尔类型的属性,用来表明cookie的值以何种形式通过网络传递。cookie默认是以不安全的形式(通过普通的,不安全的HTTP连接)被传递的。而一旦cookie被标识为“安全的”,那就只能当浏览器和服务器通过HTTPS或者其他的安全协议连接的时候才能传递它。

20.2.2 保存cookies

要给当前文档设置默认有效期的cookie值,非常简单,只需将cookie属性设置为一个字符串形式的值:

name=value

如下所示:

document.cookie = "version=" + encodeURIComponent(document.lastModified);

下次读取cookie属性的时候,之前存储的名/值对的数据就在文档的cookie列表中。由于cookie的名/值中的值是不允许包含分号,逗号和空白符,因此,在存储前一般可以采用JavaScript核心的全局函数encodeURIComponent()对值进行编码。相应的,读取cookie值的时候需要采用decodeURIComponent()函数解码。

以简单的名/值对形式存储的cookie数据有效期只在当前web浏览器的会话内,一旦用户关闭浏览器,cookie数据就丢失了。如果想要延长cookie的有效期,就需要设置max-age属性来指定cookie的有效期。按照如下的字符串形式即可:

name=value; max-age=seconds
下面的函数用来设置一个cookie的值,同时提供可选的max-age属性:
// 以名/值的形式存储cookie
// 同时采用encodeURIComponent()函数进行编码,来避免分号、逗号和空白符
// 如果daysToLive是一个数字, 设置max-age属性为该数值表示cookie直到制定的天数到
//了才会过期。如果daysToLive是0就表示删除cookie。
function setCookie(name, value, daysToLive) {
var cookie = name + "=" + encodeURIComponent(value);
if (typeof daysToLive === "number")
cookie += "; max-age=" + (daysToLive*60*60*24);
document.cookie = cookie;
}

同样的,如果要设置cookie的path,domain和secure属性,只需在cookie值存储前,以如下字符串形式追加在cookie值的后面:

; path=path
; domain=domain
; secure

要想改变cookie的值,需要使用相同的名字、路径和域,但是新的值重新设置cookie。同样的,设置新max-age属性就可以改变原来的cookie的有效期。

要想删除一个cookie,需要以相同的名字、路径和域,然后指定一个任意(非空)的值,以及将max-age属性指定为0,重新设置一次cookie。

20.2.3 读取cookies

使用JavaScript来读取cookie属性的时候,其返回的值是一个字符串,该字符串都是由一系列名值对组成,不同名值对之间通过“分号和空格”分开,其内容包含了所有作用在当前文档的cookie。但是,它并不包含其他设置的cookie属性。通过document.cookie属性可以获取cookie的值,但是为了更好的查看cookie的值,一般会采用split()方法,将cookie值中的名值对都分离出来。

把cookie的值分离出来之后,必须要采用相应的解码方式(取决于之前存储cookie值时采用的编码方式),把值还原出来。比方说,先采用decodeURIComponent()方法把cookie值解码出来,之后再利用JSON.parse()方法转化成json对象。

例20-1,定义了一个getCookie()函数,该函数将document.cookie属性的值解析出来,将对应的名值对,存储到一个对象中,函数最后返回该对象。

例 20-1. 解析document.cookies属性值

// 将document.cookie的值以一个名值对形式组成的对象返回
// 假设cookie的值存储的时候是采用encodeURIComponent()函数编码的
function getCookies() {
var cookies = {};                     // 初始化最后要返回的对象
var all = document.cookie;     // 获取所有的cookie值
if (all === "")                     // 如果该cookie属性值为空
return cookies;                     // 返回一个空对象
var list = all.split("; ");             // 分离出名值对
for(var i = 0; i < list.length; i++) {                   // 循环每对数据
var cookie = list[i];
var p = cookie.indexOf("=");                     // 查找第一个“=”符号
var name = cookie.substring(0,p);           // 获取名字
var value = cookie.substring(p+1);          // 获取对应的值
value = decodeURIComponent(value);   // 对其值进行解码
cookies[name] = value;                            // 将名值对存储到对象中
}
return cookies;
}

20.2.4 Cookie的局限性

Cookie的设计初衷是给服务端脚本用来存储少量数据的,该数据会在每次请求中传递到服务器端。 RFC 2965 鼓励浏览器供应商对cookie的数目和大小不做限制。可是,要知道,该标准不允许浏览器保存超过300个cookie,为每个Web服务器保存的cookie数不能超过20个(是对整个服务器而言,而不仅仅指服务器上的页面和站点),而且,每个cookie保存的数据不能超过4KB(即名字和值的总量不能超过4KB的限制)。实际上,现代浏览器允许cookie总数超过300个,但是部分浏览器对单个cookie大小仍然后4KB的限制。

20.2.5 Cookie相关的存储

例20-2,展示了如何实现基于cookie的一系列存储API方法。该例定义了一个CookieStorage函数(被实例化的时候具有构造器特性),通过将max-age和path属性传递给该构造器,就会返回一个对象,然后就可以像使用localStorage和sessionStorage一样来使用这个对象了。但是要注意的是,该例中并没有实现存储事件,因此,当你设置和查询CookieStorage对象的属性的时候,不会实现自动保存和获取对应的值。

例20-2. 实现基于cookie的存储API

/*
* CookieStorage.js
* 本类实现像localStorage和sessionStorage一样的存储API,不同的是,基于HTTP Cookies.
*/
function CookieStorage(maxage, path) { // 两个参数分别代表了存储有效期和作用域
// 获取一个存储全部cookie信息的对象
var cookies = (function() { // 类似之前介绍的getCookies()方法
var cookies = {}; // 该对象最终会返回
var all = document.cookie; // 以大字符串的形式获取所有cookie信息
if (all === "") // 如果该属性为空
return cookies; //返回一个空对象
var list = all.split("; "); // 分离出名值对
for (var i = 0; i < list.length; i++) { // 循环每对数据
var cookie = list[i];
var p = cookie.indexOf("="); // 查找第一个“=”符号
var name = cookie.substring(0, p); // 获取名字
var value = cookie.substring(p + 1); // 获取对应的值
value = decodeURIComponent(value); // 对其值进行解码
cookies[name] = value; // 将名值对存储到对象中
}
return cookies;
} ());

// 将所有cookie的名字存储到一个数组中
var keys = [];
for (var key in cookies) keys.push(key);

// 现在定义存储API公共的属性和方法
// 存储的cookie的个数
this.length = keys.length;

// 返回第n个cookie的名字, 如果n越界则返回null
this.key = function(n) {
if (n < 0 || n >= keys.length) return null;
return keys
;
};

// 返回指定名字的cookie值, 如果不存在则返回null.
this.getItem = function(name) {
return cookies[name] || null;
};

// 存储cookie值
this.setItem = function(key, value) {
if (! (key in cookies)) { // 如果要存储的cookie还不存在
keys.push(key); // 将指定的名字加入到存储所有cookie名的数组中
this.length++; // cookie个数加一
}
// 将该名/值对数据存储到cookie对象中
cookies[key] = value;
// 开始正式设置cookie
// 首先将要存储的cookie的值进行编码,同时创建一个“名字=编码后的值”形式的字符串
var cookie = key + "=" + encodeURIComponent(value);
//将cookie的属性也加入到该字符串中
if (maxage) cookie += "; max-age=" + maxage;
if (path) cookie += "; path=" + path;
// 通过document.cookie属性来设置cookie
document.cookie = cookie;
};

// 删除指定的cookie
this.removeItem = function(key) {
if (! (key in cookies)) return; // 如果不存在,则什么也不做
// 从内部维护的cookie删除指定的cookie
delete cookies[key];

// 同时将cookie中的名字也在内部的数组中删除
// 如果使用ES5定义的数组 indexOf()方法会更加简单
for (var i = 0; i < keys.length; i++) { // 循环所有的名字
if (keys[i] === key) { //当我们找到了要找的那个
keys.splice(i, 1); // 将它从数组中删除
break;
}
}
this.length--; // cookie个数减一
// 最终通过将该cookie值设置为空字符串以及将有效期设置为0来删除指定的cookie.
document.cookie = key + "=; max-age=0";
};

// 删除所有的cookie
this.clear = function() {
// 循环所有的cookie的名字,并将cookie删除
for (var i = 0; i < keys.length; i++)
document.cookie = keys[i] + "=; max-age=0";
// 重置所有的内部状态
cookies = {};
keys = [];
this.length = 0;
};
}

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: