Java web 前端面试知识点总结
分享一下我的面试知识点总结:
耦合性:也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息
内聚性:又称块内联系。指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。若一个模块内各元素(语名之间、程序段之间)联系的越紧密,则它的内聚性就越高。
TCP/IP五层模型:
应用层:是体系结构中的最高。直接为用户的应用进程提供服务。在因特网中的应用层协议很多,如支持万维网应用的HTTP协议,支持电子邮件的SMTP协议,支持文件传送的FTP协议等等。
运输层:运输层主要使用以下两种协议:
(1) 传输控制协议TCP(Transmission Control Protocol):面向连接的,数据传输的单位是报文段,能够提供可靠的交付。
(2) 用户数据包协议UDP(User Datagram Protocol):无连接的,数据传输的单位是用户数据报,不保证提供可靠的交付,只能提供“尽最大努力交付”。
网络层:负责为分组交换网上的不同主机提供通信服务。在发送数据时,网络层把运输层残生的报文段或用户数据报封装成分组或包进行传送。在TCP/IP体系中,由于网络层使用IP协议,因此分组也叫做IP数据报,或简称为数据报。
数据链路层:网桥(现已很少使用)、以太网交换机(二层交换机)、网卡(其实网卡 是一半工作在物理层、一半工作在数据链路层)
物理层:在物理层上所传数据的单位是比特。物理层的任务就是透明地传送比特流。
三次握手:(三次握手和四次挥手详见:http://www.cnblogs.com/ainyi/p/8629149.html)
所谓的“三次握手”即对每次发送的数据量是怎样跟踪进行协商使数据段的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送、接收完毕后何时撤消联系,并建立虚连接。
第一次
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
http协议:重中之重 在应用层
协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
HTTP协议,即超文本传输协议(Hypertext transfer protocol)。是一种详细规定了浏览器和万维网(WWW = World Wide Web)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。
HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。
在Internet中所有的传输都是通过TCP/IP进行的。HTTP协议作为TCP/IP模型中应用层的协议也不例外。HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。如下图所示:(SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。)
HTTP默认的端口号为80,HTTPS的端口号为443。
浏览网页是HTTP的主要应用,但是这并不代表HTTP就只能应用于网页的浏览。HTTP是一种协议,只要通信的双方都遵守这个协议,HTTP就能有用武之地。比如咱们常用的QQ,迅雷这些软件,都会使用HTTP协议(还包括其他的协议)。
二、简史
它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定义了今天普遍使用的一个版本——HTTP 1.1。
三、特点
HTTP协议永远都是客户端发起请求,服务器回送响应。这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。
HTTP协议的主要特点可概括如下:
1、支持客户/服务器模式。支持基本认证和安全认证。
2、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
4、HTTP 0.9和1.0使用非持续连接:限制每次连接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后,即断开连接。HTTP 1.1使用持续连接:不必为每个web对象创建一个新的连接,一个连接可以传送多个对象,采用这种方式可以节省传输时间。
5、无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。
无状态协议:
协议的状态是指下一次传输可以“记住”这次传输信息的能力。
http是不会为了下一次连接而维护这次连接所传输的信息,为了保证服务器内存。
比如客户获得一张网页之后关闭浏览器,然后再一次启动浏览器,再登陆该网站,但是服务器并不知道客户关闭了一次浏览器。
由于Web服务器要面对很多浏览器的并发访问,为了提高Web服务器对并发访问的处理能力,在设计HTTP协议时规定Web服务器发送HTTP应答报文和文档时,不保存发出请求的Web浏览器进程的任何状态信息。这有可能出现一个浏览器在短短几秒之内两次访问同一对象时,服务器进程不会因为已经给它发过应答报文而不接受第二期服务请求。由于Web服务器不保存发送请求的Web浏览器进程的任何信息,因此HTTP协议属于无状态协议(Stateless Protocol)。
HTTP协议是无状态的和Connection: keep-alive的区别:
无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。从另一方面讲,打开一个服务器上的网页和你之前打开这个服务器上的网页之间没有任何联系。
HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是UDP协议(无连接)。
从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。
Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。
四、工作流程
一次HTTP操作称为一个事务,其工作过程可分为四步:
1)首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作开始。
2)建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
3)服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
4)客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。
如果在以上过程中的某一步出现错误,那么产生错误的信息将返回到客户端,有显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,用户只要用鼠标点击,等待信息显示就可以了。
HTTP是基于传输层的TCP协议,而TCP是一个端到端的面向连接的协议。所谓的端到端可以理解为进程到进程之间的通信。所以HTTP在开始传输之前,首先需要建立TCP连接,而TCP连接的过程需要所谓的“三次握手”。下图所示TCP连接的三次握手。
在TCP三次握手之后,建立了TCP连接,此时HTTP就可以进行传输了。一个重要的概念是面向连接,既HTTP在传输完成之间并不断开TCP连接。在HTTP1.1中(通过Connection头设置)这是默认行为。
HTTP状态码:
100-199:表示信息性代码,标示客户端应该采取的其他动作,请求正在进行。
200-299:表示客户请求成功。
300-399:表示用于已经移走的资源文件,指示新的地址。 重定向
400-499:表示由客户端引发的错误。
500-599:表示由服务器端引发的错误。
404 没找到页面(not found)
403 禁止访问(forbidden)
200 一切正常(ok)
302/307 临时重定向
301 永久重定向
304 没有被修改(not modified)(服务器返回304状态,表示源文件没有被修改)从缓存中读取
设置状态码sendError(code,”Resource Not Found”);
按照响应信息的格式,先有状态行,再有消息体,所以注意在使用PrintWriter向客户端输出信息之前,设置状态码
设置HTTP响应头
目的用于告诉客户端
发送回来的内容的类型
有多少内容被正被发送
发送内容的服务器的类型
设置响应头的方法:setHeader()或setHeaders()。注意:设置响应头只能是HTTP协议。所以setHeader和setHeaders()都是HttpServletResponse中的方法
设置HTTP消息体
response.getWriter()获得打印字符流,可以输出文本
response.getOutputStream()获得输出字节流,可以发送二进制数据。
重定向原理
重定向调用方法:
response.sendRedirect(“http://127.0.0.1:8080/lovobook/bar.html“);
1,浏览器向服务器发送HTTP请求。
2,服务器接收到请求后,如果调用response.sendRedirect()方法,表示资源已被移走。则发送一个302的状态码和location的响应头。在location响应头指明要转发的地址。 302:临时重定向
3,浏览器在接收到302状态码后,会读取location响应头的内容,并将地址栏的值赋为location响应头的内容。从而再向服务器发出第二次请求。由于是二次请求,所以重定向不能获得封装在request中的属性信息
内部转发和重定向的区别:
转发是服务器行为,重定向是客户端行为
转发的速度快;重定向速度慢
1、内部转发由requestDispatcher发出,重定向由response发出。
2、内部转发是一次请求,重定向是两次不同请求。
3、内部转发可以取出request中封装的数据(携带参数),重定向不能。
4、转发地址栏没有变化,重定向地址栏有变化
5、内部转发只能在服务器内部进行,重定向可以请求别的服务器。
5、转发不会执行转发后的代码,重定向会执行重定向之后的代码
在servlet中调用转发、重定向的语句如下:
//转发到
request.getRequestDispatcher("new.jsp").forward(request, response);
//重定向
response.sendRedirect("new.jsp");
在controller层转发、重定向语句如下:
//转发
@RequestMapping("/index")
public String index(){
//some code
return "index/index"; //默认是转发,不会显示转发路径
}
@RequestMapping("/index")
public ModelAndView index(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index/index"); //默认转发,跳到此页面
return modelAndView;
}
上述转发的路径是转发到存放jsp页面的路径,就是index文件夹下的index.jsp。
但如果加上forward,
就是转发到controller层的控制类下的方法(命名空间/RequestMapping)
return "forward:index/index";
modelAndView.setViewName("forward:index/index");
//重定向 (加上redirect)
@RequestMapping("/index")
public String index(){
//some code
return "redirect:index/index"; //地址栏显示重定向路径
}
@RequestMapping("/index")
public ModelAndView index(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:index/index");
return modelAndView;
}
若要返回命名空间的上一级,用../
转发过程:客户浏览器发送http请求,web服务器接受此请求,调用内部的一个方法在容器内部完成请求处理和转发动作,将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。
重定向过程:客户浏览器发送http请求,web服务器接受后发送302状态码响应及对应新的location给客户浏览器,客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址,服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。
重定向,其实是两次request
第一次,客户端request A,服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。
JSP九大内置对象
在翻译好的类中,在_jspService()中有九个局部变量,并都做了初始化。由于我们在JSP中书写的内容都是丰富_jspService()方法,所以可以直接使用这些局部变量,这就是隐式对象
四个作用域:
page:在一个页面内保存属性,跳转之后无效。page对象代表JSP本身,只有在JSP页面内才是合法的。
request:作用于请求 :在一次服务请求范围内,服务器跳转后依然有效,request对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据
session:作用于会话 :在一次会话范围内,无论何种跳转都可以使用,但是关闭浏览器后,新开浏览器无法使用。session对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态
application:作用于全局(类型是ServletContext) :整个服务器上保存,所有用户都可以使用。application对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效
response:代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端
out:对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区pageContext 对象的作用是取得任何范围的参数
config:对象的主要作用是取得服务器的配置信息
exception:对象的作用是显示异常信息
关系型数据库遵循ACID规则
事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性:
事务的特性:
1、A (Atomicity) 原子性
原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。
比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。
2、C (Consistency) 一致性
一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。
例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。
3、I (Isolation) 独立性
所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。
比如现在有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。
4、D (Durability) 持久性
持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。
session 和 cookie
1.由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。
2. 思考一下服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
3. Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?这个信息可以写到Cookie里面,访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户。这也是Cookie名称的由来,给用户的一点甜头。
所以,总结一下:
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。存储量太小,只有 4KB
下面介绍HTTP协议定义的缓存机制。
Expires策略
Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
注:Date头域表示消息发送的时间,时间的描述格式由rfc822定义。例如,Date: Mon,31 Dec 2001 04:25:57GMT。
Web服务器告诉浏览器在2012-11-28 03:30:01这个时间点之前,可以使用缓存文件。发送请求的时间是2012-11-28 03:25:01,即缓存5分钟。
不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。
Cache-control策略(重点关注)
Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。
http协议头Cache-Control : |
值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age 各个消息中的指令含义如下:
|
还是上面那个请求,web服务器返回的Cache-Control头的值为max-age=300,即5分钟(和上面的Expires时间一致,这个不是必须的)。
Last-Modified/If-Modified-Since
Last-Modified/If-Modified-Since要配合Cache-Control使用。
l Last-Modified:标示这个响应资源的最后修改时间。由服务器往客户端发送的http头,web服务器在响应请求时,告诉浏览器资源的最后修改时间。
l If-Modified-Since:响应资源最后修改的时间,由客户端往服务端发送的头。再次请求本地存在的 cache 页面时,客户端会通过 If-Modified-Since 头将先前服务器端发过来的 Last-Modified 最后修改时间戳发送回去,这是为了让服务器端进行验证,通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回200,返回新的内容。如果是最新的,则 返回 304 告诉客户端其本地 cache 的页面是最新的,于是客户端就可以直接从本地加载页面了,这样在网络上传输的数据就会大大减少,同时也减轻了服务器的负担。
Etag/If-None-Match
Etag/If-None-Match也要配合Cache-Control使用。
l Etag:服务端往客服端发送的头。web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
l If-None-Match:(Etags的值),客户端往服务端发送的头。工作原理是在HTTP Response中添加ETags信息。当客户端再次请求该资源时,将在HTTP Request中加入If-None-Match信息(ETags的值)。如果服务器验证资源的ETags没有改变(该资源没有改变),将返回一个304状态;否则,服务器将返回200状态,并返回该资源和新的ETags。
既有Last-Modified为何还要Etag?
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
l Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
l 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存
l 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
用户行为与缓存
浏览器缓存行为还有用户的行为有关!!!
用户操作 |
Expires/Cache-Control |
Last-Modified/Etag |
地址栏回车 |
有效 |
有效 |
页面链接跳转 |
有效 |
有效 |
新开窗口 |
有效 |
有效 |
前进、后退 |
有效 |
有效 |
F5刷新 |
无效 |
有效 |
Ctrl+F5刷新 |
无效 |
无效 |
总结
浏览器第一次请求:
浏览器再次请求时:
从输入URL到页面加载完成的过程中都发生了什么事情?
- 输入地址URL
- 利用DNS查找域名的 IP 地址
这一步包括 DNS 具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存... - 根据IP建立TCP连接(三次握手)
- 浏览器向 web 服务器发送一个 HTTP 请求
- 服务器的永久重定向响应(从 http://example.com 到 http://www.example.com)
- 浏览器跟踪重定向地址
- 服务器处理请求
- 服务器返回一个 HTTP 响应
- 浏览器渲染页面,构建DOM树,显示 HTML
- 浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
- 浏览器发送异步请求
HTTP 协议中 URI 和 URL 有什么区别?
统一资源标志符URI:就是在某一规则下能把一个资源独一无二地标识出来。
拿人做例子,身份证号就是URI,通过身份证号能让我们能且仅能确定一个人。
统一资源定位符URL:也拿人做例子:动物住址协议://地球/中国/浙江省/杭州市/西湖区/某大学/14号宿舍楼/525号寝/张三.人
可以看到,这个字符串同样标识出了唯一的一个人,起到了URI的作用,所以URL是URI的子集。URL是以描述资源的位置来唯一确定一个资源的。
所以不论是用定位的方式还是用编号的方式,我们都可以唯一确定一个人,都是URl的一种实现,而URL就是用定位的方式实现的URI。
回到Web上,假设所有的Html文档都有唯一的编号,记作html:xxxxx,xxxxx是一串数字,即Html文档的身份证号码,这个能唯一标识一个Html文档,那么这个号码就是一个URI。
而URL则通过描述是哪个主机上哪个路径上的文件来唯一确定一个资源,也就是定位的方式来实现的URI。
JavaScript事件流:
事件传播的顺序对应浏览器的两种事件流模型:捕获型事件流和冒泡型事件流。
DOM标准采用捕获+冒泡。两种事件流都会触发DOM的所有对象,从document对象开始,也在document对象结束。
DOM标准规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。
事件捕获阶段:实际目标(<div>)在捕获阶段不会接收事件。也就是在捕获阶段,事件从document到<html>再到<body>就停止了。上图中为1~3.
处于目标阶段:事件在<div>上发生并处理。但是事件处理会被看成是冒泡阶段的一部分。上图中为4
冒泡阶段:事件又传播回文档。上图中为5~7
阻止事件冒泡:
若有一a标签:
<a href="http://www.baidu.com" target="_blank"></a>
1.event.stopPropagation()方法
这是阻止事件的冒泡方法,不让事件向documen上蔓延,但是默认事件任然会执行,当你掉用这个方法的时候,如果点击一个连接,这个连接仍然会被打开,不会冒泡到父元素直至document
2.event.preventDefault()方法
这是阻止默认事件的方法,调用此方法是,连接不会被打开,但是会发生冒泡,冒泡会传递到上一层的父元素;
3.return false ;
这个方法比较暴力,他会同时阻止事件冒泡也会阻止默认事件;写上此代码,连接不会被打开,事件也不会传递到上一层的父元素;可以理解为return false就等于同时调用了event.stopPropagation()和event.preventDefault(),但可以在return false之前执行一些必要代码。但标签内部的事件不会执行
跨域问题
了解同源政策:所谓"同源"指的是"三个相同"。
- 协议相同
- 域名相同
- 端口相同
同源政策的目的:是为了保证用户信息的安全,防止恶意的网站窃取数据。
设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。
由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。
解决跨域问题:
首先假设你请求数据的网站为B。要看你是否可以控制(修改里面的代码)。
1 jsonp 缺点:只能get请求 ,需要修改B网站的代码
2 cors 这个方案缺点 是 ie6 7 兼容不好(倒是不见得要兼容)。需要B网站在响应中加头
3 postMessage 缺点也是 ie6 7 兼容不好(倒是不见得要兼容)。需要修改B网站的代码
4 iframe window.name 传值得方式很巧妙,兼容性也很好。但是也是需要你能修改B网站代码
5 服务端主动请求B网站,兼容性好而且你客户端的代码还是原来的ajax,缺点是感觉不好。(服务器端是不存在跨域安全限制的)
6 类似5 用nginx把B网站的数据url反向代理。
如果你不能修改B网站的代码老老实实5 6 方案
如果能修改B网站 方案2的修改应该是最简单的。
就算是B网站你可以修改,还有种需求处理起来比较麻烦的,就是有的数据需要登录之后才能取。
最直接的方案,B网站提供数据的url 进去先提供用户名密码,走下登录再走取数据,最后返回数据。
Jsonp解决跨域:
1 $.ajax({ 2 3 url:url, 4 5 dataType:'jsonp', 6 7 processData: false, 8 9 type:'get', 10 11 success:function(data){ 12 13 alert(data.name); 14 15 }, 16 17 error:function(XMLHttpRequest, textStatus, errorThrown) { 18 19 alert(XMLHttpRequest.status); 20 21 alert(XMLHttpRequest.readyState); 22 23 alert(textStatus); 24 25 } 26 27 });
jsonp其实返回的是一个JS函数调用代码,把返回的数据和客户端能调用的函数名拼接在一起,放到浏览器环境下,去执行而得到最终的服务端数据,也就是jsonp是一种json数据的传输方式而不是格式
jsonp格式:
callback({
"message":"获取成功",
"state":"1",
"result":{"name":"工作组1","id":1,"description":"11"}
})
jsonp 的实现原理,详情看:https://github.com/Krryxa/WORK-LEARNING/issues/23
介绍一下闭包和闭包常用场景
闭包是指有权访问另一个函数作用域中的局部变量的函数. 创建闭包常见方式,就是在一个函数内部创建另一个函数.
应用场景 设置私有变量和方法
不适合场景:返回闭包的函数是个非常大的函数
闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
为什么会出现闭包这种东西,解决了什么问题
受JavaScript链式作用域结构的影响,父级变量中无法访问到子级的变量值,为了解决这个问题,才使用闭包这个概念
详情看:https://github.com/Krryxa/WORK-LEARNING/issues/20
语义化:
像html5的新的标签header,footer,section等就是语义化
一方面,语义化就是让计算机能够快速的读懂内容,高效的处理信息,可以对搜索引擎更友好。
另一方面,便于与他人的协作,他人通过读代码就可以理解你网页标签的意义。
box-sizing属性:
content-box 是W3C的标准盒模型 元素宽度=内容宽度+padding+border
border-box 是ie的怪异盒模型 他的元素宽度等于内容宽度, 内容宽度包括了 padding+border,只要设定了宽度高度,再设置padding 和 border 也不会撑大
比如有时候在元素基础上添加内距padding或border会将布局撑破 但是使用border-box就可以轻松完成
Inherit:规定应从父元素继承 box-sizing 属性的值。
介绍一下HTML5的新特性
- 新的DOCTYPE声明 <!DOCTYPE html>
- 完全支持css3
- video和audio
- 本地存储
- 语义化标签 <header><nav><aside><article><footer>
- Canvas图形
- 新事件 如ondrag onresize
- HTML5 拖放
- 地理定位
Css3 新特性:
圆角边框border-radius,添加阴影框 box-shadow / text-shadow
颜色渐变
2d 3d 转换:transform
过度 transition
动画 @keyframes
媒体查询 @media 响应式优化
语义化标签:
HTML5增加了新的内容标签,这些标签带有一定的语义,使搜索引擎爬取你的网站信息更高效。
HTML4中的内容标签级别相同,无法区分各部分内容。而HTML5中的内容标签互相独立,级别不同,搜索引擎以及统计软件等均可快速识别各部分内容。
本地存储(Local Storage)
最早的Cookies自然是大家都知道,问题主要就是太小,大概也就4KB的样子,而且IE6只支持每个域名20个cookies,太少了。
在HTML5中,本地存储是一个window的属性,包括localStorage和sessionStorage,从名字应该可以很清楚的辨认二者的区别,前者是一直存在本地的,后者只是伴随着session,窗口一旦关闭就没了。二者用法完全相同
- localStorage - 没有时间限制的数据存储
- sessionStorage - 针对一个 session 的数据存储
Label的作用是什么?是怎么用的?
label标签来定义表单控制间的关系,当用户选择该标签时,浏览器会自动将焦点转到和标签相关的表单控件上。
<label for="Name">Number:</label>
<input type=“text“name="Name" id="Name"/>
<label>Date:<input type="text" name="B"/></label>
拖拽
是一种常见的特性,即抓取对象以后拖到另一个位置。在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放。
设置元素为可拖放
首先,为了使元素可拖动,把 draggable 属性设置为 true :
- <img draggable="true">
当离开的时候 ondragleave
当进入的时候ondragenter
拖动什么 - ondragstart 和 setData()
放到何处 - ondragover :内部移动
进行放置 - ondrop
原生ajax:
1 //创建一个FormData对象:用一些键值对来模拟一系列表单控件:即把form中所有表单元素的name与value组装成一个queryString 2 3 var form = new FormData(); 4 5 //设置要传递的参数 6 7 form.append("doc", fileObj); 8 9 // 创建一个ajax对象 10 11 var xhr = new XMLHttpRequest(); 12 13 //规定请求的类型、URL 以及是否异步处理请求。true为异步 14 15 //请求是异步的。因为要实时获取到上传的进度,则请求需是异步的,如果是同步的话,会直到请求完成才能获取到响应 16 17 xhr.open("post", url, true); 18 19 //发送http请求:将请求发送到服务器,与后台交互 20 21 xhr.send(form); //也可以不携带参数,直接 xhr.send(); 22 23 //响应成功进入的回调函数 24 25 xhr.onreadystatechange = function(){ 26 27 //状态4和200代表和服务器端交互成功 28 29 if(xhr.readyState==4 && xhr.status==200){ 30 31 //获取上传成功的返回数据 32 33 var data = xhr.responseText.trim(); 34 35 jdata = eval("("+data+")"); 36 37 } 38 39 };
//xhr.open() 与 xhr.send() 一起用
//前者是规定请求的类型、url,后者是发送请求到这个url
浏览器兼容问题解决:
问题一:不同浏览器的标签默认的外补丁和内补丁不同
- 问题症状:随便写几个标签,不加样式控制的情况下,各自的margin 和padding差异较大。
- 碰到频率:100%
- 解决方案:css里 *{margin:0;padding:0;}
- 备注:这个是最常见的也是最易解决的一个浏览器兼容性问题,几乎所有的css文件开头都会用通配符*来设置各个标签的内外补丁是0。通配符*代表所有的
css3特殊子元素选择器:
:last-child 选择元素最后一个孩子
:first-child 选择元素第一个孩子
:nth-child(1) 按照第几个孩子给它设置样式
:nth-child(even) 按照偶数
:nth-child(odd) 按照奇数
css3伪类:
a:link {color: #FF0000} /* 未访问的链接 */
a:visited {color: #00FF00} /* 已访问的链接 */
a:hover {color: #FF00FF} /* 鼠标移动到链接上 */
a:active {color: #0000FF} /* 选定的链接 */
:after 选择器在被选元素的内容后面插入内容。使用 content 属性来指定要插入的内容。
js 删除数组几种方法
详情看:https://github.com/Krryxa/WORK-LEARNING/issues/9
Array 对象方法
连接两个或更多的数组,并返回结果。 |
|
把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。 |
|
删除并返回数组的最后一个元素(改变原数组) |
|
向数组的末尾添加一个或更多元素,并返回新的长度。(改变原数组) |
|
颠倒数组中元素的顺序。(改变原数组) |
|
删除并返回数组的第一个元素(改变原数组) |
|
从某个已有的数组返回选定的元素 |
|
对数组的元素进行排序(改变原数组) |
|
删除元素,并向数组添加新元素。(改变原数组) |
|
返回该对象的源代码。 |
|
把数组转换为字符串,并返回结果。 |
|
把数组转换为本地数组,并返回结果。 |
|
向数组的开头添加一个或更多元素,并返回新的长度。(改变原数组) |
|
返回数组对象的原始值 |
详情看:https://github.com/Krryxa/WORK-LEARNING/issues/9
箭头函数不绑定this,arguments,自家没有this,找的是上一级的this
如何更改this指向:
1) new、call、apply、bind
2) let _this = this;
3) => 箭头函数
如何确定this是谁,看谁调动的, .前面是谁this就是谁
第一种: new关键字改变this指向
1 // 构造函数版 this 2 function Fn(){ 3 this.user = "筱月"; // 此时的 this 指向 window 4 } 5 let a = new Fn(); 6 console.log(a.user); //筱月
用变量a创建了一个 Fn 的实例,此时仅仅只是创建,并没有执行,而调用这个函数 Fn 的是对象 a,那么 this 指向的自然是对象 a,那么为什么对象 a 中会有 user,因为你已经复制了一份 Fn 函数到对象 a 中,用了 new 关键字就等同于复制了一份
第二种: call()
注意如果 call 和 apply 的第一个参数写的是null,那么 this 指向的是 window 对象
1 let a = { 2 user:"筱月", 3 fn:function(){ 4 console.log(this.user); //筱月 5 } 6 } 7 let b = a.fn; 8 // 执行 b 方法,call 的第一个参数是改变 this 指向,b 方法的 this 就是指向 call 第一个参数的对象 9 b.call(a); // 若不用call,则 b() 执行后 this 指的是 Window 对象
// call方法除了第一个参数以外还可以添加多个参数,如下: let a = { user:"筱月", fn:function(e,ee){ console.log(this.user); // 筱月 console.log(e+ee); // 3 } } let b = a.fn; b.call(a,1,2); // 输出 筱月 3
第三种:apply()
1 let a = { 2 user:"筱月", 3 fn:function(){ 4 console.log(this.user); //筱月 5 } 6 } 7 8 let b = a.fn; 9 b.apply(a); 10 11 // apply方法和call方法有些相似,它也可以改变this的指向,也可以有多个参数,但是不同的是,第二个参数必须是一个数组,如下: 12 13 let a = { 14 user:"筱月", 15 fn:function(e,ee){ 16 console.log(this.user); //筱月 17 console.log(e+ee); //11 18 } 19 } 20 21 let b = a.fn; 22 b.apply(a,[10,1]); 23 24 // 注意如果 call 和 apply 的第一个参数写的是null,那么this指向的是window对象 25 26 let a = { 27 user:"筱月", 28 fn:function(){ 29 console.log(this); // Window {...} 30 } 31 } 32 33 let b = a.fn; 34 b.apply(null);
第四种:bind()
bind方法和call、apply方法有些不同,如下:
bind 方法返回的是一个修改过后的函数,此时并没有调用,需要将 bind 方法返回的函数执行 才能调用
1 let a = { 2 user:"筱月", 3 fn:function(){ 4 console.log(this.user); //筱月 5 } 6 7 } 8 let b = a.fn; 9 let c = b.bind(a); // 方法还没执行,bind 方法返回的是一个修改过后的函数 10 c(); // 输出:筱月 11 12 // 同样bind也可以有多个参数,并且参数可以在 bind 返回的函数执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的 13 let aa = { 14 user:"筱月", 15 fn:function(e,d,f){ 16 console.log(this.user); //筱月 17 console.log(e,d,f); //10 1 2 18 } 19 } 20 21 let bb = aa.fn; 22 let cc = bb.bind(aa,10); // 可以添加参数 23 cc(1,2); // 执行的时候可以继续添加参数
总结: call 和 apply 都是改变上下文中的 this 并立即执行这个函数,bind 方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别
let _this = this
这里就将外部的 this 放进 callback 里面,callback 里面就可以使用外部的 this
var a = function(){ } 和function b(){ } 有什么区别
function b(){} 为函数声明,程序运行前就已存在;
var a = function(){} 为函数表达式,属于按顺序执行,所以a为undefined
1 //代码一: 2 3 a(1); //执行这个会报错 4 5 var a = function(index){ 6 7 alert(index); 8 9 } 10 11 a(2); //执行这个不会报错
1 //代码二: 2 3 a(1); //执行这个不会报错 4 5 function a(index){ 6 7 alert(index); 8 9 } 10 11 a(2); //执行这个不会报错