LocalStorage
localStorage的优势
- localStorage拓展了cookie的4K限制
- localStorage会可以将第一次请求的数据直接存储到本地,这个相当于一个5M大小的针对于前端页面的数据库,相比于cookie可以节约带宽,但是这个却是只有在高版本的浏览器中才支持的
localStorage的局限
- 浏览器的大小不统一,并且在IE8以上的IE版本才支持localStorage这个属性
- 目前所有的浏览器中都会把localStorage的值类型限定为string类型,这个在对我们日常比较常见的JSON对象类型需要一些转换
- localStorage在浏览器的隐私模式下面是不可读取的
- ocalStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡
- localStorage不能被爬虫抓取到
- localStorage与sessionStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空这里我们以localStorage来分析。
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if(!window.localStorage){ alert("浏览器支持localstorage"); returnfalse; }else{ var storage=window.localStorage; //写入a字段 storage["a"]=1; //写入b字段 storage.b=2; //写入c字段 storage.setItem("c",3); console.log(typeof storage["a"]); console.log(typeof storage["b"]); console.log(typeof storage["c"]); } |
运行后的结果如下:
这里要特别说明一下localStorage的使用也是遵循同源策略的,所以不同的网站直接是不能共用相同的localStorage
最后在控制台上面打印出来的结果是:
不知道各位读者有没有注意到,刚刚存储进去的是int类型,但是打印出来却是string类型,这个与localStorage本身的特点有关,localStorage只支持string类型的存储。
localStorage的读取
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
if(!window.localStorage){ alert("浏览器支持localstorage"); }else{ var storage=window.localStorage; //写入a字段 storage["a"]=1; //写入b字段 storage.b=2; //写入c字段 storage.setItem("c",3); console.log(typeof storage["a"]); console.log(typeof storage["b"]); console.log(typeof storage["c"]); //第一种方法读取 var a=storage.a; console.log(a); //第二种方法读取 var b=storage["b"]; console.log(b); //第三种方法读取 var c=storage.getItem("c"); console.log(c); } |
localStorage就是相当于一个前端的数据库的东西,数据库主要是增删查改这四个步骤,这里的读取和写入就相当于增、查的这两个步骤
下面我们就来说一说localStorage的删、改这两个步骤
改这个步骤比较好理解,思路跟重新更改全局变量的值一样,这里我们就以一个为例来简单的说明一下。
JS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
if(!window.localStorage){ alert("浏览器支持localstorage"); }else{ var storage=window.localStorage; //写入a字段 storage["a"]=1; //写入b字段 storage.b=1; //写入c字段 storage.setItem("c",3); console.log(storage.a); // console.log(typeof storage["a"]); // console.log(typeof storage["b"]); // console.log(typeof storage["c"]); /*分割线*/ storage.a=4; console.log(storage.a); } |
删除localStorage
- 将localStorage的所有内容清除
JS
1 2 3 4 5 6 |
var storage=window.localStorage; storage.a=1; storage.setItem("c",3); console.log(storage); storage.clear(); console.log(storage); |
- 将localStorage中的某个键值对删除
JS
1 2 3 4 5 6 |
var storage=window.localStorage; storage.a=1; storage.setItem("c",3); console.log(storage); storage.removeItem("a"); console.log(storage.a); |
- 控制台查看结果
localStorage的键获取
JS
1 2 3 4 5 6 7 |
var storage=window.localStorage; storage.a=1; storage.setItem("c",3); for(var i=0;i<storage.length;i++){ var key=storage.key(i); console.log(key); } |
参考Window localStorage 属性 | 菜鸟教程
cookie
2. 什么是cookie
HTTP协议本身是无状态的。什么是无状态呢,即服务器无法判断用户身份。Cookie实际上是一小段的文本信息(key-value格式)。客户端向服务器发起请求,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。
打个比方,我们去银行办理储蓄业务,第一次给你办了张银行卡,里面存放了身份证、密码、手机等个人信息。当你下次再来这个银行时,银行机器能识别你的卡,从而能够直接办理业务。
3. cookie机制
当用户第一次访问并登陆一个网站的时候,cookie的设置以及发送会经历以下4个步骤:
客户端发送一个请求到服务器 –》 服务器发送一个HttpResponse响应到客户端,其中包含Set-Cookie的头部 –》 客户端保存cookie,之后向服务器发送请求时,HttpRequest请求中会包含一个Cookie的头部 –》服务器返回响应数据
image
为了探究这个过程,写了代码进行测试,如下:
我在doGet方法中,new了一个Cookie对象并将其加入到了HttpResponse对象中
JAVA
1 2 3 4 5 6 7 |
protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { Cookie cookie = new Cookie("mcrwayfun",System.currentTimeMillis()+""); // 设置生命周期为MAX_VALUE cookie.setMaxAge(Integer.MAX_VALUE); resp.addCookie(cookie); } |
浏览器输入地址进行访问,结果如图所示:
可见Response Headers中包含Set-Cookie头部,而Request Headers中包含了Cookie头部。name和value正是上述设置的。
4. cookie属性项
属性项 | 属性项介绍 |
NAME=VALUE | 键值对,可以设置要保存的 Key/Value,注意这里的 NAME 不能和其他属性项的名字一样 |
Expires | 过期时间,在设置的某个时间点后该 Cookie 就会失效 |
Domain | 生成该 Cookie 的域名,如 domain=”www.baidu.com“ |
Path | 该 Cookie 是在当前的哪个路径下生成的,如 path=/wp-admin/ |
Secure | 如果设置了这个属性,那么只会在 SSH 连接时才会回传该 Cookie |
Expires
该属性用来设置Cookie的有效期。Cookie中的maxAge用来表示该属性,单位为秒。Cookie中通过getMaxAge()和setMaxAge(int maxAge)来读写该属性。maxAge有3种值,分别为正数,负数和0。
如果maxAge属性为正数,则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中(每个浏览器存储的位置不一致)。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。下面代码中的Cookie信息将永远有效。
JAVA
1 2 3 4 |
Cookie cookie = new Cookie("mcrwayfun",System.currentTimeMillis()+""); // 设置生命周期为MAX_VALUE,永久有效 cookie.setMaxAge(Integer.MAX_VALUE); resp.addCookie(cookie); |
当maxAge属性为负数,则表示该Cookie只是一个临时Cookie,不会被持久化,仅在本浏览器窗口或者本窗口打开的子窗口中有效,关闭浏览器后该Cookie立即失效。
JAVA
1 2 3 4 |
Cookie cookie = new Cookie("mcrwayfun",System.currentTimeMillis()+""); // MaxAge为负数,是一个临时Cookie,不会持久化 cookie.setMaxAge(-1); resp.addCookie(cookie); |
可以看到,当MaxAge为-1时,时间已经过期
当maxAge为0时,表示立即删除Cookie
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Cookie[] cookies = req.getCookies(); Cookie cookie = null; // get Cookie for (Cookie ck : cookies) { if ("mcrwayfun".equals(ck.getName())) { cookie = ck; break; } } if (null != cookie) { // 删除一个cookie cookie.setMaxAge(0); resp.addCookie(cookie); } |
那么maxAge设置为负值和0到底有什么区别呢?
maxAge设置为0表示立即删除该Cookie,如果在debug的模式下,执行上述方法,可以看见cookie立即被删除了。
maxAge设置为负数,能看到Expires属性改变了,但Cookie仍然会存在一段时间直到关闭浏览器或者重新打开浏览器。
修改或者删除Cookie
HttpServletResponse提供的Cookie操作只有一个addCookie(Cookie cookie),所以想要修改Cookie只能使用一个同名的Cookie来覆盖原先的Cookie。如果要删除某个Cookie,则只需要新建一个同名的Cookie,并将maxAge设置为0,并覆盖原来的Cookie即可。
新建的Cookie,除了value、maxAge之外的属性,比如name、path、domain都必须与原来的一致才能达到修改或者删除的效果。否则,浏览器将视为两个不同的Cookie不予覆盖。
值得注意的是,从客户端读取Cookie时,包括maxAge在内的其他属性都是不可读的,也不会被提交。浏览器提交Cookie时只会提交name和value属性,maxAge属性只被浏览器用来判断Cookie是否过期,而不能用服务端来判断。
我们无法在服务端通过cookie.getMaxAge()来判断该cookie是否过期,maxAge只是一个只读属性,值永远为-1。当cookie过期时,浏览器在与后台交互时会自动筛选过期cookie,过期了的cookie就不会被携带了。
Cookie的域名
Cookie是不可以跨域名的,隐私安全机制禁止网站非法获取其他网站的Cookie。
正常情况下,同一个一级域名下的两个二级域名也不能交互使用Cookie,比如test1.mcrwayfun.com和test2.mcrwayfun.com,因为二者的域名不完全相同。如果想要mcrwayfun.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数为**.mcrwayfun.com**,这样使用test1.mcrwayfun.com和test2.mcrwayfun.com就能访问同一个cookie
一级域名又称为顶级域名,一般由字符串+后缀组成。熟悉的一级域名有baidu.com,qq.com。com,cn,net等均是常见的后缀。
二级域名是在一级域名下衍生的,比如有个一级域名为mcrfun.com,则blog.mcrfun.com和www.mcrfun.com均是其衍生出来的二级域名。
Cookie的路径
path属性决定允许访问Cookie的路径。比如,设置为”/“表示允许所有路径都可以使用Cookie
sessionStroage
localStorage 和 sessionStorage 属性允许在浏览器中存储 key/value 对的数据。
sessionStorage 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。
提示: 如果你想在浏览器窗口关闭后还保留数据,可以使用 localStorage 属性, 该数据对象没有过期时间,今天、下周、明年都能用,除非你手动去删除。
this
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<body> <!-- 解析器在调用函数每次都会向函数内部传递一个隐含的参数 这个函数的参数就是this,this指向的是一个对象, 这个对象成为函数执行的上下文对象 根据函数调用方式不同,this会指向不同的对象 1.this以函数的形式调用时,this永远都是window 2.this以方法的形式调用时,this就是调用发放的那个对象 --> <script> functionfun(){ console.log(this.name) } var obj= { name:"孙悟空", sayName: fun }; var obj2= { name:"猪八戒", sayName: fun }; // console.log(obj.sayName== fun) fun(); obj.sayName(); obj2.sayName(); </script> </body> |
使用工厂方法创建对象
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<script> functionxiyouji(name,gender,age){ var per= newObject() per.name=name per.gender=gender per.age= age per.sayname= functione(){ alert(this.name) } return per; } var per1 = xiyouji("孙悟空","男","18"); var per2= xiyouji("猪八戒","男","18"); console.log(per1) console.log(per2) per2.sayname(); // function createdog(name,age){ // var dog =new Object() // dog.name = name // dog.age= age // dog.sayhello=function e(){ // alert("汪汪汪") // } // return dog; // } // var dog1=createdog("gg","6") // console.log(dog1) // dog1.sayhello() // console.log(per1) </script> |
构造函数
为了区分不同的类(人,狗),可以通过构造函数的方式来实现
构造函数执行流程:
- 立即创建一个新的对象
- 将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
- 逐行执行函数中的代码
- 将新建的对象作为返回值返回
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<script> functionPerson(name,gender,age){ this.name=name this.gender=gender this.age= age this.sayname=functione(){ alert('你好') } } var per =new Person("ch","男","21") console.log(per) per.sayname() </script> |
所有的对象都是Object()的后代
原型对象
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<scripttype="text/javascript"> /* * 创建一个构造函数 */ functionMyClass(){ } //向MyClass的原型中添加一个name属性 MyClass.prototype.name = "我是原型中的名字"; var mc = new MyClass(); mc.age = 18; //console.log(mc.name); //使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true //console.log("name" in mc); //可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性 //使用该方法只有当对象自身中含有属性时,才会返回true //console.log(mc.hasOwnProperty("age")); //console.log(mc.hasOwnProperty("hasOwnProperty")); /* * 原型对象也是对象,所以它也有原型, * 当我们使用一个对象的属性或方法时,会现在自身中寻找, * 自身中如果有,则直接使用, * 如果没有则去原型对象中寻找,如果原型对象中有,则使用, * 如果没有则去原型的原型中寻找,直到找到Object对象的原型, * Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined */ //console.log(mc.__proto__.hasOwnProperty("hasOwnProperty")); //console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); //console.log(mc.__proto__.__proto__.__proto__); //console.log(mc.hello); //console.log(mc.__proto__.__proto__.__proto__) |
总而言之,MyClass()可以当爸爸,通过MyClass()创建的对象是儿子,MyClass()则是爷爷,爷爷或者爸爸的基因从儿子身上可以显现,但不是本身创造的基因,如果要追根溯源,可以从爷爷或者爸爸身上找到这个基因,这就是构成了原型链。im