前端知识

文章目录

HTTP

http和https

http是超文本传输协议,是目前互联网上使用最多的协议。是在应用层进行传输的。
https是安全超文本传输协议,是基于http开发的,并使用了ssl(安全套接字层)进行加密的网络协议,可以说是更安全版的http。是在传输层进行传输。
区别:

  • http是明文传输,而https是使用了ssl进行加密的
  • http基于应用层,https基于传输层
  • https需要ca证书,费用高一些
  • 他们使用的是不同的连接方式,所以接口一般也不同,http使用的一般是80,https一般是443
  • https在浏览器中会显示安全锁,http就没有

https的工作流程

https的工作流程

  • 客户端发起一个https请求
  • 服务器端收到了请求之后,会将自己的公钥证书返回给客户端
  • 客户端验证公钥证书,如果不通过则显示警告信息,如果通过则继续
  • 客户端使用伪随机数生成器生成加密所使用的对称密钥,然后用证书中的公钥加密对称秘钥发送给服务器,以此通知服务器,之后的报文都会通过这个对称秘钥来加密。
  • 服务器用自己的私钥解密这个消息,得到对称秘钥,这时候,客户端和服务器端都持有了相同的对称密钥,之后就可以使用对称秘钥来进行加密解密了

https的作用

建立安全通道,确保数据的安全与完整,以及验证对方的身份,缺点就是贵和慢

http响应头的一些字段

http字段
在这里插入图片描述

content-type的属性和作用

content-type决定如何展示返回的消息内容
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式

http返回的状态码

200:请求成功,一般用于get/post请求
201:已创建,成功请求并创建了新的资源
202:已接受,但是未完成处理
304:如果客户端发送了一个带条件的GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个304状态码。(也就是执行了get请求 但是文件并没有改变)
400:客户端请求的语法错误,服务器无法理解
403:请求资源的访问被服务器拒绝,没有权限访问
404:找不到页面
500:服务器内部错误

HTTP请求方式的8中请求方法

get、post、head(前三个是http1.0)、options、put、delete、trace和connect(后面是http1.1新增的)

  • get:请求指定的页面信息,并返回实体主体(一般用在查询)
  • head:类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
  • post:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。post请求可能会导致新的资源建立或已有资源的修改
  • put:从客户端向服务器传送新数据,替代原有的
  • delete:删除指定页面/数据
  • connect:预留给能够将连接改为管道方式的代理服务器
  • options:列出可对资源实行的请求方法,用来跨域请求
  • trace:回显服务器收到的请求,主要用于测试或诊断

get和post的区别:

  • get参数通过url传递,post放在request body中
  • get请求在url中传递的参数是有长度限制的(这个长度限制并不是http去限制的,而是浏览器/服务器限制的),而post没有
  • post比get更安全,因为参数直接暴露在url中,所以不能用来传递敏感信息
  • get请求会被浏览器主动cache,post不会,除非手动设置
  • get请求只能进行url编码,post支持多种编码方式
  • get请求的参数会被完整保存在浏览器历史记录中,而post中的参数不会被保留
  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • get和post本质都是tcp链接,并无差别,都是由于http的规定和浏览器/服务器的限制,导致他们在应用中体现了一些不同
  • get产生一个tcp数据包,post产生两个tcp数据包(很像get一趟就送到了数据,post则需要两次,第一次告诉你我要传递数据,第二次才正式传送数据)
  • 他们在缓存上面的区别,get请求类似于查找,所以不需要每次都连接数据库,可以使用缓存,而post一般做添加/修改操作,需要跟数据库连接,不能使用缓存

在地址栏里输入一个URL,到这个页面呈现出来,中间会发生什么?(http的工作流程)

  • 拿到ip:DNS解析拿到ip和对应的端口号(首先根据用户输入的URL地址查找服务器的ip,如果缓存或者系统的host中有则直接拿到ip,如果没有则需要查询DNS服务器)
  • 与服务器建立tcp连接
  • 浏览器根据ip和端口号发起http请求
  • 服务器响应请求,返回对应的数据
  • 浏览器下载数据,并解析源文件,渲染页面,呈现页面

TCP的三次握手和四次挥手

三次握手:

(为什么不是两次?无法确认客户端的接收能力)
(为什么不是四次?为了解决问题,三次就足够了,再多用处就不大了)

  • 客户端向服务器端发送一段TCP报文,请求建立连接
  • 服务器端接收到了之后,返回确认收到请求,以及同意创建连接的信息
  • 客户端收到消息后,明确了从客户端到服务器端是可以正常发送数据的,然后客户端就向服务器端发送确认收到消息,至此,两边都可以相互正常发送消息,建立连接
    在这里插入图片描述
    (1)首先客户端向服务器端发送一段TCP报文,其中:标记位为SYN,表示“请求建立新连接”;序号为Seq=X(X一般为1);随后客户端进入SYN-SENT阶段。
    (2)服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,其中:
    标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);序号为Seq=y;确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。
    (3)客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。其中:
    标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;随后客户端进入ESTABLISHED阶段。

四次挥手:

  • 客户端想要断开连接,向服务器端发送请求断开连接的报文
  • 服务器端收到后,开始进入准备释放的状态,并返回收到请求断开连接的消息
  • 服务器端做好了释放的准备,再次向客户端发送已经准备好释放的消息
  • 客户端收到准备好的消息后,向服务器端发送收到准备好的信息
    在这里插入图片描述

TCP和UDP的区别:

  • tcp需要先建立连接再发送数据,而udp是无连接的,发送数据前不需要先建立连接
  • tcp提供的是可靠的服务,而udp是尽最大努力交付,不保证可靠交付
  • tcp面向字节流,udp面向报文传输
  • tcp传输效率没有udp传输效率高
  • tcp只能一对一传输,而udp可以一对一,一对多

WebSocket

websocket只需要完成一次握手,就可以在客户端和服务器端之间建立持久的连接,并且服务器端和客户端可以相互发送多个数据
在这里插入图片描述

http2.0

1996年,发布了HTTP的1.0版本,这一版才加入了大量的内容,使得互联网不仅可以传输文字,还能传输图像、视频、二进制文件等,报文格式也规定下来,引入了post和head等命令,是第一个比较成熟的版本。然而,1.0版本的主要缺点是每个HTTP连接只能发送一个请求(短连接),发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。这就会带来很多不必要的开销。
  1997年,发布了HTTP的1.1版本,这一版将HTTP更加完善,直到现在还是主要的使用版本。1.1 版的最大变化,就是引入了持久连接(长连接),在响应完第一个请求之后,TCP连接默认不关闭,可以被多个请求复用,这样就客服了1.0版本的缺陷。除此之外,还引入了管道机制:一次可以发送多个请求,增加了put、delete等命令。
  2015年,HTTP/2 发布(不叫 HTTP/2.0,不再发布子版本,下一个是3),HTTP2的变化在于(1)二进制协议,头信息和数据体都是二进制,统称为帧(头信息帧和数据帧)。(2)多工,双向实时通信,复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。(3)数据流。据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。(4)头信息压缩机制。**(5)允许服务器推送。**允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。

缓存

cookie的作用

保存用户的登录状态,用户在下次进入页面就不需要再登录了,可以提示用户多久不需要登录;跟踪用户行为,例如一个天气预报网站,能够根据用户选择的地区显示当地的天气情况。

cookie的使用

document.cookie创建一个cookie字符串,里面的设置属性就行,它是一个字符串,可以用字符串的一些方法获取属性值。
document.cookie="name=Nicholos;expries=time"等等

cookie的一些属性字段

  • name字段:一个cookie的名称
  • value字段:一个cookie的值
  • domain字段:可以访问此cookie的域名
  • path字段:可以访问此cookie的页面路径
  • Size字段:此cookie大小
  • http字段:cookie的httponly属性,若此属性为True,则只有在http请求头中会有此cookie信息,而不能通过document.cookie来访问此cookie。
  • secure字段:设置是否只能通过https来传递此条cookie。
  • expires/Max-Age字段:设置cookie超时时间。如果设置的值为一个时间,则当到达该时间时此cookie失效。不设置的话默认是session,意思是cookie会和session一起失效,当浏览器关闭(并不是浏览器标签关闭,而是整个浏览器关闭)后,cookie失效。
    在这里插入图片描述

cookie、sessionStorage、localStorage的区别

相同点:都存储在客户端
不同点

  • 存储大小,cookie存储的数据大小不超过4k,而sessionStorage和localstorage的存储大小可以达到5M
  • 有效时间,cookie可以由用户设置保存的时间,到了时间就会自动清除,localstorage存储持久数据,浏览器关闭后数据也不会丢失,除非主动删除数据,sessionstorage在当前浏览器窗口关闭后自动就删除了
  • 数据与服务器之间的交互方式,cookie的数据会自动传递给服务器,服务器端也可以写入cookie到客户端,而sessionstorage和localstorage不会自动把数据发给服务器,仅在本地保存

cookie和session的区别:

  • cookie的数据存储在客户端浏览器上,session的数据保存在服务器上
  • cookie的存储容量顶多为4k,session没有上限,当然出于对性能的考虑,也不能随便存,应设置session删除机制
  • 有效期上不同,cookie可以设置存储时间,session则只需要关闭session窗口就会失效
  • cookie对客户端是可见的,别有用心的人可以分析存放在本地的cookie并进行cookie,是不安全的,session是存储在服务器端,不存在敏感信息泄露的风险
  • cookie保存在客户端,不占用服务器资源,对于并发用户很多的网站,cookie是很好的选择,而session是保存在服务器端,每个用户都会产生一个session,如果并发访问的用户很多,会产生很多的session,耗费大量的内存

强缓存和协商缓存

浏览器缓存分为强缓存和协商缓存
强缓存就是首先判断头部信息,没过期就直接从缓存中读取数据(cache-control)
强缓存是利用http头中的ExpiresCache-Control两个字段来控制,
Expires 它的值是一个绝对的时间,这个时间代表资源的失效时间,就是说在这个时间之前缓存始终有效,始终会读取缓存中的数据。但是,这里会有一个明显的缺点:因为它是一个绝对时间,当服务器时间与客户端时间有偏差时,就可能会导致缓存失效,比如用户随意修改了本地时间…
**Cache-Control:**表示资源的最大有效时间的“秒数”,是一个相对值,不会因为用户修改本地时间而导致失效。
协商缓存就是需要服务器去判断是否数据更新过,如果没有则继续采用缓存中的数据,返回304,如果有则采用更新的数据,返回200(etag:每个文件唯一,Last-Modified)
Last-Modified/If-Modified-Since 和 ETag/If-None-Match
Last-Modified/If-Modified-Since:
  1) 浏览器第一次发送请求,让服务端在response header中返回请求的资源上次更新时间(Last-Modified的值),浏览器会存下这个时间;
  2)当浏览器下次请求时,request header中带上If-Modified-Since(即保存的Last-Modified的值)。根据浏览器发送的修改时间和服务端的修改时间进行比对,一致的话代码资源没有改变,服务端返回正文为空的响应,让浏览器在缓存中读取资源,从而减少请求消耗。
ETag/If-None-Match:
  1) 浏览器第一次发送一个请求得到ETag的值,然后在下一次请求request header中带上If-none-match(即保存的ETag的值);
  2)通过发送的ETag的值和服务器重新生成的ETag的值进行比对,如果一致代表资源没有改变,服务器返回的正文为空的响应,让浏览器从缓存中读取资源,从而减少请求消耗。
  在这里插入图片描述

前端优化

合并资源,减少http请求(合并资源、合并css、js文件、合理使用缓存)
在这里插入图片描述
在这里插入图片描述
CDN简单来说,就是加速,当一个网站开启了CDN加速,其给用户的感觉是访问网站速度或者下载东西的速度会明显比没有开启加速更快,变快或者下载东西变快了。
当网站开启CDN,用户访问该网站,并非直接访问该网站的原服务器,而是一个服务器分发的离你最近的一个服务器节点,由于服务器离你近了,所以访问速度或者下载速度会更快。
在这里插入图片描述
在这里插入图片描述

OSI七层模型

在这里插入图片描述

HTML

html5和css3中新增

html5:

  • 增加了一些语义标签来更好的创建页面结构,例如
    等等
  • HTML5 Input 类型,例如date、url等等
  • HTML5 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成。 标签只是图形容器,您必须使用脚本来绘制图形。
  • HTML5 拖放
    拖放是一种常见的特性,即抓取对象以后拖到另一个位置。在 HTML5中,拖放是标准的一部分,任何元素都能够拖放。
    设置元素为可拖放
    首先,为了使元素可拖动,
<img draggable="true">

a.拖动什么 - ondragstart 和 setData()

b.放到何处 - ondragover

c.进行放置 - ondrop

  • 地理定位
  • Audio(音频)、Video(视频)
  • HTML5 Web 存储,sessionstorage和localstorage
    css3:
  • CSS3边框如border-radius,box-shadow等;
  • CSS3背景如background-size,background-origin等;
  • CSS3 2D,3D转换如transform等;
  • CSS3动画如animation等

meta标签属性有哪些?

meta标签用来提供页面的一些信息

  • charset属性
  • name + content属性
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0, user-scalable=no"/>
<!-- 
  viewport参数详解:
  width:宽度(数值 / device-width)(默认为980 像素)
  height:高度(数值 / device-height)
  initial-scale:初始的缩放比例 (范围从>010)
  minimum-scale:允许用户缩放到的最小比例
  maximum-scale:允许用户缩放到的最大比例
  user-scalable:用户是否可以手动缩 (no,yes)
 -->
  • http-equiv(expires设置过期时间,set-cookie)

src和href的区别是什么?

  • href(a,link)是Hypertext Reference的简写,表示超文本引用,指向网络资源所在位置
  • src(img,script)是source的简写,目的是要把文件下载到html页面中去
  • 浏览器遇到href会并行下载资源,不会停止对当前文档的处理(建议link而不是@import),而src会先暂停,直到该资源加载或执行完毕(script放在底部,而不是头部的原因)

script标签中defer和async的区别是什么

  • 当script中有defer属性时,脚本的加载过程和文档加载是异步发生的,等到文档解析完(DOMContentLoaded事件发生)脚本才开始执行。
  • 当script有async属性时,脚本的加载过程和文档加载也是异步发生的。但脚本下载完成后会停止HTML解析,执行脚本,脚本解析完继续HTML解析。
  • 当script同时有async和defer属性时,执行效果和async一致。

svg和canvas和区别:

SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
一句话总结:都是2D做图,svg是矢量图,canvas是位图。Canvas 是逐像素进行渲染的,适合游戏。
在这里插入图片描述

CSS

盒子模型:

用来装页面上元素的矩形区域,盒子模型包括IE盒子模型和标准盒子模型
box-sizing设置盒子模型

box-sizing:content-box;//默认值,标准盒模型 内容真正宽度=设置的宽度
box-sizing:border-box;//内容真正宽度=设置的width-左右padding-左右border
box-sizing:padding-box;//把padding计算到content里面(有的地方说有,有的说没有)
box-sizing:inhert;//规定从父元素继承此值

标准盒子模型:width就是指的是content
IE盒子模型(怪异盒子模型):width包括content、padding和border

flex布局

弹性布局,传统的布局时依赖display属性+position+float属性,非常不方便,比如实现垂直居中就很不方便
display:flex声明弹性布局,任何元素都可以声明为弹性布局,inline-flex行内元素弹性布局,声明flex之后子元素的float、clear和vertical-align属性就失效了
容器属性:flex-direction,flex-wrap、flex-flow、justify-content、align-item、align-content
内部元素属性:order、flex-grow、flex-shrink、flex-basis、flex、align-self
order属性:定义项目的排列顺序,顺序越小,排列越靠前,默认为0
flex-grow属性:定义项目的放大比例,即使存在空间,也不会放大
flex-shrink属性:定义了项目的缩小比例,当空间不足的情况下会等比例的缩小,如果定义个item的flow-shrink为0,则为不缩小
flex-basis属性:定义了在分配多余的空间,项目占据的空间。
flex:是flex-grow和flex-shrink、flex-basis的简写,默认值为0 1 auto。
align-self:允许单个项目与其他项目不一样的对齐方式,可以覆盖align-items,默认属性为auto,表示继承父元素的align-items
flex-direction:决定主轴的方向

.box {
    display:flex;
    //row水平,从左到右,row-reverse从右到左,column垂直从上到下,column-reverse垂直从下到上
    flex-direction: row | row-reverse | column | column-reverse;
}

flex-wrap:决定换行方式

.box{
    //nowrap不换行,wrap换行,直接在下面换行, wrap-reverse换行到原有到的上面
  flex-wrap: nowrap | wrap | wrap-reverse;
}

flex-flow:flex-direction和flex-wrap属性的简写方式,默认为row|nowrap

.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}

justify-content:元素在主轴上的对齐方式

.box {
    //flex-start左对齐(默认),flex-end右对齐,center居中,space-between两端对齐,元素之间的间隔相等,
    //space-around每个元素两侧的间隔相等,元素之间的间隔是两边元素离边界距离的两倍
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

align-item:在交叉轴上的对齐方式

.box {
    //flex-start交叉轴起点对齐,flex-end交叉轴终点对齐,center居中对齐,
    //baseline元素第一行文字的基线对齐,stretch(默认)如果元素未设置高度,将占满整个容器
  align-items: flex-start | flex-end | center | baseline | stretch;
}

align-content定义多根轴线的对齐方式

.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

BFC:块级格式化上下文

格式化上下文,即为一个独立的区域,内部有自己的一套渲染规则,规定了内部的元素的定位规则,以及与其他元素的关系和相互作用
BFC
格式化上下文,浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为"visiable"的块级盒子,都会为他们的内容创建新的BFC
BFC渲染规则
(1)BFC内部垂直方向边距重叠,两个bfc不会重叠
(2)BFC的区域不会与浮动元素的box重叠
(3)BFC是一个独立的容器,外面的元素不会影响里面的元素
(4)计算BFC高度的时候浮动元素也会参与计算
应用场景:

  • 防止浮动导致父元素高度塌陷
  • 避免外边距折叠

实现垂直居中的几种方式:

居中元素有宽高

  • absolute+负margin
//需要居中的元素
.box {
    position: absolute;
    width:100px;
    height:100px;
    top: 50%;//相对于父元素
    left: 50%;
    margin-left: -50px;//让元素向相反的方向偏移子元素的一半
    margin-top: -50px;
}
  • absolute+margin auto
.box {
    position: absolute;;
    width:100px;
    height:100px;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}
  • absolute+calc
.box {
    position: absolute;
    width:100px;
    height:100px;
    top: calc(50% - 50px);//calc动态计算长度值。
    left: calc(50% - 50px);
}

居中元素没有宽高:

  • absolute+transform
.box {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);//相对于自身的宽和高去偏移
}
  • flex布局
.parent{
    display: flex;
    justify-content: center;
    align-items: center;
}

块元素、行内元素、行内块元素

  • 块元素:独占一行,并且有自动填满父元素,可以设置margin和pading以及高度和宽度
  • 行元素:不会独占一行,width和height会失效,并且在垂直方向的margin、padding会失
    效,仅左右有效。
  • 行内块元素:综合两者,行内的块元素

隐藏元素,opacity=0,visibility=hidden,display=none

opacity=0,设置透明度为100%,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click事件,那么点击该区域,也能触发点击事件。
visibility=hidden,该元素隐藏起来了,不会改变页面布局,但是不会触发该元素已经绑定的事件。
display=none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉一样。

position属性比较

  • fixed:固定定位,元素的位置相对于浏览器窗口来说是固定的
  • relative:相对定位,相对于原来自身的定位,移动的时候会覆盖其他的元素,一般与absolute一起用
  • absolute:绝对定位,相对于最近的已定位的父级元素。absolute 定位使元素的位置与文档流无关,因此不占据空间。 absolute 定位的元素和其他元素重叠。
  • static:默认值,不加定位
  • inherit:继承父级元素的定位

清除浮动

  • 使用带clear属性的空元素
    在浮动元素后使用一个空元素如<div class="clear"></div>,并在CSS中赋予.clear{clear:both;}属性即可清理浮动。亦可使用<br class="clear" /><hr class="clear" />来进行清理。
  • 父级添加overflow(hidden)属性,或者设置高度
  • 建立伪类选择器清除浮动,在css中添加:after伪元素
//在css中添加:after伪元素
.parent:after{
    /* 设置添加子元素的内容是空 */
      content: '';  
      /* 设置添加子元素为块级元素 */
      display: block;
      /* 设置添加的子元素的高度0 */
      height: 0;
      /* 设置添加子元素看不见 */
      visibility: hidden;
      /* 设置clear:both */
      clear: both;
}
<div class="parent">
    <div class="f"></div>
</div>

css选择器以及优先级

id选择器,类选择器、标签选择器、后代选择器(空格 只要是后代都可以)、子元素选择器(>只能是父子关系)、伪类选择器(a:hover)等(伪类和伪元素不一样,伪类的操作对象是文档树中已有的元素,而伪元素则创建了一个文档树外的元素。
同一元素引用了多个样式时,排在后面的样式属性优先级高
样式选择器的类型不同时,id选择器>class选择器>标签选择器
标签之间存在层级包含关系时,后代元素会继承父级元素的样式,后代的样式会覆盖父级
带有!importan优先级最高
内联样式>内部样式>外部样式

z-index:设置元素的堆叠顺序

什么是标签语义化?

合理的标签去做合理的事情,便于开发者阅读和写出更优雅的代码,同时让浏览器的爬虫和机器很好地解析。

圣杯布局(左右固定,中间自适应)

html,body,.father {
            display: flex;
            width: 100%;
            height: 100%;
        }

        .left,
        .right {
            width: 200px;
            background-color: blue;
        }

        .center {
            flex: 1;
            background-color: red;
        }

移动端响应式布局(一个网站能够兼容多个终端,手机、pad、等等)开发的几大方案

  • media:通过媒体查询写不同的样式(移动端和web端使用同一套项目)
  • rem:两套不同的项目,pc端用px,移动端rem
  • flex:局部的会用到flex

em和rem的区别:

他们的大小都不是固定的,只是相对父级/html元素的

  • rem:rem的大小是以html为基准的,大小就是html的字体大小*数值
  • em:是根据父元素字体大小设置的

隐藏超过的部分

white-space: nowrap; //文本不换行。
overflow: hidden; //超过部分隐藏
text-overflow: ellipsis; //超过部分用…代替

过渡transition:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box{
            width: 200px;
            height: 200px;
            background-color: green;
            margin: 100px auto;
            /* 过渡:过渡的属性 时间 方式 延迟时间 */
            transition: all 2s linear 0s;

            
        }
        .box:hover{
            width: 500px;
            background-color: orange;
        }
    </style>
</head>
<body>
    <div class="box"></div>
</body>
</html>

缩放与旋转:transform

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box{
            width: 200px;
            height: 200px;
            background-color: green;
            margin: 100px auto;
            //加过渡让旋转慢一点
            transition: all 5s;

            
        }
        .box:hover{
            /* transform:scale:放大缩小; */
            /* transform: scale(2,0.5); */

            /* transform:rotate旋转,正值顺时针,负值逆时针 */
            /* transform-origin设置以谁旋转 */
            /* transform-origin: bottom center;
            transform: rotate(360deg); */

            /* 3d转换 */
            /* rotateY绕Y轴旋转多少度 */
            transform: rotateY(360deg);
            background-color: orange;
        }
    </style>
</head>
<body>
    <div class="box"></div>
</body>
</html>

动画animation:

css动画详解

一个时钟的例子

//一个时钟的例子
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box{
            width: 3px;
            height: 200px;
            background-color:black;
            margin: 100px auto;
            transform-origin: center bottom;
            /* animation: 定义的动画名称  持续时间  执行次数  是否反向  运动曲线 延迟执行。(infinite 表示无限次) */
            animation: myClock 60s steps(60) infinite;
            
        }
        @keyframes myClock{
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }
    </style>
</head>
<body>
    <div class="box"></div>
</body>
</html>

Animation和Transtion的异同

在这里插入图片描述

如何画一个三角形

div{
    width:0;
    height:0;
    border:50px solid;
    border-color:red tranplate tranplate tranplate;
}

border本质不是长方形的边框,而是三角形

如何画一条0.5px的线?

1.采用meta viewport方式(viewport只针对移动端)

<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5"/>

2.采用transform:scale()方式

transform: scale(0.5,0.5);//transform表示2d/3d的旋转、缩放、移动、倾斜等,scale就是缩放

link标签和import标签的区别

  • link属于html标签,而@import是css提供的
  • 页面被加载时,link会同时被加载,而@import会在页面加载完再加载
  • link是html标签,不存在兼容性的问题,@import老版本不支持
  • link权重高于@import
  • 使用DOM控制元素的不同,JS控制页面样式时只能用link,@import不是DOM可以控制的

JavaScript

es6添加

  • const与let变量
    在这里插入图片描述

  • 模板字面量,在es6之前,将字符串拼接在一起的方法是+或者concat方法,而模板字面量可以用``(反引号),再使用${}表示占位符

  • 解构,在es6中可以使用解构从数组和对象中提取值并赋予给独特的变量

  • for…of(不需要计数器i,忽略索引)循环结合了for(需要计数器)和for…in(需要索引)的优势,仅仅只是循环访问对象中的值(注意forEach仅仅是数组的方法)

  • 展开运算符:…连续三个点,将字面量(字符串字面量、数组字面量、对象字面量、函数字面量)展开为多个元素(展开数组)
    箭头函数

闭包

闭包是指有权访问另一个函数作用域中的变量的函数,也就是能够读取另一个函数作用域中变量的函数。
闭包的作用: 正常函数执行完毕后,里面声明的变量被垃圾回收处理掉,但是闭包可以让作用域里的变量,在函数执行完之后依旧保持没有被垃圾回收处理掉
正常情况下函数在调用完就会被销毁,但是闭包就是去阻止这件事情发生的
闭包的缺点:
内存泄漏(在退出函数之前,将不使用的局部变量全部删除),this指向的问题
在这里插入图片描述

new操作符做了哪些事情

new操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象
new操作符都干了些什么?

  • 创建一个空对象obj,然后把这个空对象的__proto__设置为构造函- 数的prototype
  • 初始化实例:构造函数被传入参数并调用,关键字this被设定指向该实例
  • 返回obj对象

this指向

  • 如果是一般函数,this指向全局对象window;
  • 在严格模式下"use strict",为undefined.
  • 对象的方法里调用,this指向调用该方法的对象.
  • 构造函数里的this,指向创建出来的实例.

this绑定规则

在这里插入图片描述

修改this绑定的函数

apply和call改变函数的this指向,基本没啥区别,主要是参数不同,第一个参数都是要改变指向的对象,第二个是传入的参数,apply是数组,而call是arg1,arg2…
通过bind改变this作用域会返回一个新的函数,这个函数不会马上执行
bind不会立即执行,apply和call会立即执行

手写call、apply和bind

手写call

Function.prototype.myCall = function(context) {
    if (typeof context === "undefined" || context === null) {
        context = window
    }
   //context=context||window  和上面的代码一样
    context.fn = this
    const args = [...arguments].slice(1)
    const result = context.fn(...args)
    delete context.fn
    return result
}

实现分析:

  • 首先context为可选参数,如果不传的话默认上下文是window
  • 接下来给content创建一个fn属性,并将值设置为需要调用的函数
  • 因为call可以传入多个参数作为调用函数的参数,所有需要将参数剥离出来
  • 然后调用函数并将对象上的函数删除
    手写apply
    实现与call类似,只不过是参数是数组形式
Function.prototype.myApply = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    context = context || window
    context.fn = this
    let result
    if (arguments[1]) {
        result = context.fn(...arguments[1])
    } else {
        result = context.fn()
    }
    delete context.fn
    return result
}

手写bind

Function.prototype.myBind = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    //返回一个绑定this的函数,这里我们需要保存this
    const _this = this
    const args = [...arguments].slice(1)
        //返回一个函数
    return function F() {
        //因为返回一个函数,我们可以new F()需要判断能当做构造函数吗
        if (this instanceof F) {
            return new _this(...args, ...arguments)
        }
        return _this.apply(context, args.concat(...arguments))
    }
}
  • bind返回一个函数,对于函数来说有两种方式调用,一种是直接调用,一种是通过new的方式,我们先来说直接调用的方式
  • 对于直接调用来说,这里选择了apply的方式,但是对于参数需要注意以下情况:因为bind可以实现类似这样的代码 f.bind(obj,1)(2),所以我们需要将两边的参数拼接起来,于是就有了这样的实现args.concat(…arguments)
  • new的方式,我们先判断this,对于new的情况,不会被任何方式改变this,所以对于这种情况我们需要忽略传入的this
    测试mycall
var student = {
  name: 'xiaoming'
}

function showAge(age) {
  console.log(`My name is ${this.name}, I am ${age} years old.`)
}

showAge.myCall(student, 18) // My name is xiaoming, I am 18 years old.

js基本数据类型

基本的(es5):undefined、null、number、Boolean、string
引用数据类型:object、function、array等等
还有一个symbol(es6):用给定名称作为唯一标识,确保唯一,及时采用相同的名称,也会产生不同的值
堆:存储引用类型值的空间
栈:存储基本数据类型、指定代码的环境

基本类型和引用类型的区别

上面的除了object,其余都是基本类型,object又包括数组、对象、函数等
区别如下

  • 引用类型的值是可变的,而基本类型是不可变的
  • 引用类型的比较不仅会比较值,也会比较存储的地址是否一致,而基本类型是比较值
  • 基本类型的赋值是简单赋值,引用类型赋值会发生关联,是浅拷贝
  • 基本类型存储在栈中,引用类型存储在堆中
    (堆和栈的区别:栈一般存放简单的数据,更新快,类型占据的空间是一定的,堆一般存储数组/对象,而堆是由垃圾回收机制去销毁变量的)

js判断数据类型:

  • typeof():只能返回一些number、boolean、string这些基本的数据类型,很多的引用类型返回object(比如数组,对象等等)
  • Object.prototype.toString.call()
  • instanceof:判断两个对象是否属于实例关系

null和undefined的区别

  • null表示“没有对象,即此处不应该有值”。被定义了,但是为null
  • undefined表示“缺少值”,即此处应该有一个值,但是没有定义。没定义
    null==undefined为true的原因是他们的类型转换后不一样,但是规定就是相等
    null三个等于undefined为false

==、===和object.is()的区别

  • 两个等于:两边类型如果不同的时候先进行类型转换,再比较
  • 三个等于:就是严格的比较,不做类型转换,类型不同就不等
  • object.is():与===基本一致,但是有两个不一样的地方:在object.is()中,1.+0不等于-0;2.NaN等于自身

==的转换规则:

转换规则如下:

  • 两边的类型是否相同,相同的话就比较值的大小,例如1==2,返回false
  • 判断的是否是null和undefined,是的话就返回true
  • 判断的类型是否是String和Number,是的话,把String类型转换成Number,再进行比较
  • 判断其中一方是否是Boolean,是的话就把Boolean转换成Number,再进行比较
  • 如果其中一方为Object,且另一方为String、Number或者Symbol,会将Object转换成字符串,再进行比较

js的垃圾回收机制

垃圾回收机制就是为了防止内存泄漏(内存泄漏就是当已经不需要模块内存时,但是这块内存还存在着)垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存
(c#、java、JavaScript都有自动垃圾回收机制,c/c++没有垃圾回收机制)
js垃圾回收有两种方式:标记清除和引用计数

  • 标记清除:(经常用的)变量进入执行环境(函数中声明变量)的时候,垃圾回收器就将其标记为‘进入环境’,当变量离开环境的时候(函数执行结束),将其标记为‘离开环境’,垃圾收集器给所有的变量都加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的标记。
  • 引用计数:(常常会引起内存泄漏,低版本的IE使用这种方式),机制就是跟踪一个值的引用次数,当声明一个变量并将一个引用类型赋值给该变量时,该值引用次数加1,当这个变量指向其他一个时,该值的引用次数便减1,当该值引用次数为0时,就会被回收

类的创建和继承

类的创建:new一个function,可以直接在function中定义属性和方法,也可以在这个function的prototype里面添加属性和方法
类的继承:

  • 原型继承
function Parent2() {
    this.name = 'parent2';
    this.play = [1, 2, 3]
  }
  function Child2() {
    this.type = 'child2';
  }
  Child2.prototype = new Parent2();

  console.log(new Child2());

容易实现,父类新增原型属性和方法,子类都能访问到,缺点就是原型属性在所有实例中都是共享的,无法实现多继承

  • 构造继承
    方法:在子类构造函数中通过使用apply和call等方法调用父类的构造函数
  function Parent1(){
    this.name = 'parent1';
  }
  function Child1(){
    Parent1.call(this);
    this.type = 'child1'
  }
  console.log(new Child1);

可以实现多继承,只能继承实现父类实例的属性和方法,不能继承原型上的属性和方法

  • 组合继承
    构造继承和原型链继承的组合体,可以继承实例属性/方法,也可以继承原型属性/方法
 function Parent5 () {
    this.name = 'parent5';
    this.play = [1, 2, 3];
  }
  function Child5() {
    Parent5.call(this);
    this.type = 'child5';
  }
  Child5.prototype = Object.create(Parent5.prototype);
  Child5.prototype.constructor = Child5;

es6中有class和extends,可以使用组合(compose来进行组合继承层,有选择的继承父类的方法)

箭头函数与普通函数的区别:

  • 箭头函数没有this(this指向JavaScript实例,只有在函数调用的时候才可以被确定下来),所以如果出现了this,绑定的就是最近一层非箭头函数的this
  • 箭头函数没有自己的arguments(函数的参数数组)对象,(但是可以通过rest来获取)
  • 不能通过new关键字调用,也没有原型属性

Dom0级和Dom2级的区别:

  • dom0级在绑定了多个同类型的事件,后面的效果会覆盖前面的效果(比如多个click,只会执行最后一个)
    属于dom0级的有:在标签内写onclick事件、在JS写onlicke=function(){}函数
  • dom2级在这种情况下不会覆盖,而是会有顺序的执行,
    属于二级的只有addEventListener

js异步有哪些解决方案

  • 回调当中嵌套回调,会产生回调地狱,不方便后期维护;并且每次任务可能会失败,需要在回调里面对每个任务的失败情况进行处理,增加了代码的混乱程度。
  • promise,嵌套操作就可以通过then连接的链式操作,很好了解决了回调地狱的问题,同时了合并了错误处理
  • co + Generator 方式,在function后面添加*将函数变为generator,用到yield关键字
  • async/await:async声明异步函数,await(函数等待await后的promise返回,再执行下面的语句)后面一般接一个promise对象
    (用async/await写出的代码也更加优雅、美观,相比于之前的Promise不断调用then的方式,语义化更加明显,相比于co + Generator性能更高,上手成本也更低)。

Promise 利用了三大技术手段来解决回调地狱:

回调函数延迟绑定(回调函数不是直接声明的,而是在通过后面的 then 方法传入的,即延迟传入)。
返回值穿透(会根据 then 中回调函数的传入值创建不同类型的Promise, 然后把返回的 Promise 穿透到外层, 以供后续的调用)。
错误冒泡(前面产生的错误会一直向后传递,被 catch 接收到,就不用频繁地检查错误了)。

promise对象:

实现promise的resolve、reject和fillaly、all、race,如下链接
promise对象代表了未来将要发生的事件,用来传递异步操作的信息
promise对象有两个特点:
1.对象的状态不受外界影响。promise对象代表一个异步操作,有三种状态:

  • pending:初始状态
  • fulfilled:意味着操作成功完成
  • rejected:意味着操作失败
    只有异步操作的结果,才能决定当前是哪一种状态,任何操作都无法改变这个状态

2.一旦状态改变,就不会再变,任何时候都可以得到这个结果。promise对象状态改变,只有两种可能,pending变为fulfilled和pending变为rejected。只要这两种情况发生,状态就不会再改变了,会一直保持这个结果。与事件不同的是,事件错过了就监听不到结果了。

promise的优点:有了promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
缺点:首先无法取消promise,一旦新建就立即执行,中途无法取消。其次,如果不设置回调函数,promise内部抛出的错误,不会反应到外部,第三,当处于pending状态时,无法得知目前进展到哪一阶段(刚开始还是即将完成)

promise通过new来创建,构造函数中包含带有resolve和reject两个参数的回调函数,在回调中执行一些操作,如果一切正常,则调用resolve(resolve还可以将一个对象转化为promise对象),否则reject

var promise = new Promise(function(resolve, reject) {
    // 异步处理
    // 处理结束后、调用resolve() 或 reject()
});

之后promise对象可以调用.then方法

js的语言特性

js是一门动态的、弱类型、基于原型的脚本语言
动态性:在JavaScript对象中,要为一个属性赋值,我们不必事先创建一个字段,只需要在使用的时候赋值即可
弱类型:与java、c/c++不同,js不需要特意指定具体的数据类型,能够很大程度的对一个变量进行复用
解释与编译:js是一门解释型的语言,边翻译边执行
基于原型
跨平台性好
**补充:**编译性语言和解释性语言
编译性语言,只需编译一次就可以把源代码编译成机器语言(c/c++),执行效率较高,比较依赖编译器,跨平台性差一些
解释性语言,源代码不能直接翻译成机器语言,而是先翻译成中间代码,再由解释器对中间代码进行解释运行,程序不需要编译,程序边运行边翻译,运行效率低一些,跨平台性好(JavaScript、python)

js、java、c++的区别:

  • c++和java是静态类型语言,在编译的时候就能知道每个变量的类型,在编程的时候需要给定具体的数据类型,而js运行的时候才知道每个变量的类型,编程时不需要指定具体类型
  • js是解释型语言,程序不需要编译。c++就是编译性语言,需要将源代码进行编译才能运行。java分为两个阶段将源代码编译成字节码,然后再由java虚拟机运行字节码,使用解释器执行这些代码。

浅拷贝和深拷贝的区别

浅拷贝(赋值不是拷贝,只是指向了同一个地址空间,浅拷贝是指向的两个地址空间)的限制所在。它只能拷贝一层对象。如果有对象的嵌套,那么浅拷贝将无能为力。但幸运的是,深拷贝就是为了解决这个问题而生的,它能 解决无限极的对象嵌套问题,实现彻底的拷贝。

js中string对象的indexof()和startwith()的区别:

  • stringObject.indexOf(searchvalue,fromindex):返回某个指定字符串值在字符串中首次出现的位置
  • string.startsWith(searchvalue, fromindex):检测字符串是否以指定的子字符串开头

js字符串转数字的方法:

强制转换:Number()
parseInt()/parseFloat()

js循环

  • for…in,拿到index下标
  • for…of,拿到值
  • forEach,拿到值和索引
  • 普通的for,需要用变量来依次遍历
var arr = [3, 2, 1];
// for (const key in arr) {
//     console.log(key) //0,1,2
// }

// for (const key of arr) {
//     console.log(key)//3,2,1
// }

arr.forEach((item, index) => 
{console.log(item);console.log(index)})

for…in和for…of的区别

  • for…of适用遍历数组/字符串/map/set等拥有迭代器对象的集合.但是不能遍历对象,因为没有迭代器对象.与forEach()不同的是,它可以正确响应break、continue和return语句,遍历出来的是数组中的元素,
  • for…in遍历出来的是索引index,适合遍历对象,遍历顺序有可能不是按照实际数组的内部顺序,并且会遍历所有的可枚举属性,包括原型。如果不需要原型上的属性,可以使用hasOwnProperty来判断是否是自己的属性。

可迭代对象

可以应用 for…of 的对象被称为 可迭代的。

  • 技术上来说,可迭代对象必须实现 Symbol.iterator 方法。
    obj[Symbol.iterator] 的结果被称为 迭代器(iterator)。由它处理进一步的迭代过程。
    一个迭代器必须有 next() 方法,它返回一个 {done: Boolean, value: any} 对象,这里 done:true 表明迭代结束,否则 value 就是下一个值。
  • Symbol.iterator 方法会被 for…of 自动调用,但我们也可以直接调用它。
  • 内置的可迭代对象例如字符串和数组,都实现了 Symbol.iterator。
  • 字符串迭代器能够识别代理对(surrogate pair)。(译注:代理对也就是 UTF-16 扩展字符。)

遍历对象的几种方法

for…in
Object.keys(对象)
Object.values(对象)
Object.getOwnPropertyNames(obj),返回一个数组,包含对象自身的所有属性

dom,文档对象模型

文档对象模型,定义了访问和操作HTML文档的标准方法,以树形的结构表达html文档

BOM,浏览器对象模型

浏览器对象模型,提供了独立于内容而与浏览器窗口进行交互的对象。

  • window对象:js的最顶层对象,其他的dom对象都是window对象的属性
    弹窗类:alert()等等
    定时器类:setTimeout(函数,时间)
  • document对象:文档对象
    document.getElementById:根据id获取元素
  • location对象:浏览器当前URL信息,
    location.href:返回或设置当前文档的url
    location.port:返回url中的端口部分
  • navigator对象:浏览器本身信息
    navigator.userAgent:返回用户代理头的字符串表示
    navigator.cookieEnabled:返回浏览器是否支持(启用)cookie
  • screen对象:获取用户屏幕信息
    screen.height等等等
  • history对象:浏览器访问历史信息
    history.back:后退一页
    history.forward:前进一页

原型和原型链

所有的函数都有一个prototype属性,原型对象
所有的实例都有一个__proto__属性,执行构造函数的prototype
在这里插入图片描述

同步和异步

在这里插入图片描述

常见的异步操作

在这里插入图片描述

如何实现浏览器多个页面相互通信?

  • 使用localstorage,localstorage.setItem(key,value)
  • 使用cookie+setInterval

页面渲染时js堵塞的解决办法

  • async异步加载,在script中添加async属性,边渲染边加载
  • onload异步加载,等页面的图片之类的资源全部加载完再下载执行js

重绘和回流

回流,也叫重排。当我们对 DOM 结构的修改引发 DOM 几何尺寸变化的时候,会发生回流的过程
具体一点,有以下的操作会触发回流:

  • 一个 DOM 元素的几何属性变化,常见的几何属性有width、height、padding、margin、left、top、border 等等, 这个很好理解。
  • 使 DOM 节点发生增减或者移动。
  • 读写 offset族、scroll族和client族属性的时候,浏览器为了获取这些值,需要进行回流操作。
  • 调用 window.getComputedStyle 方法。
    在这里插入图片描述
    需要重新生成dom树,相当于将解析和合成的过程重新又走了一遍,开销是非常大的
    重绘,当 DOM 的修改导致了样式的变化,并且没有影响几何属性的时候,会导致重绘(repaint)。
    由于没有导致 DOM 几何属性的变化,因此元素的位置信息不需要更新,从而省去布局的过程。流程如下:
    在这里插入图片描述
    跳过了生成布局树和建图层树的阶段,直接生成绘制列表,然后继续进行分块、生成位图等后面一系列操作。
    可以看到,重绘不一定导致回流,但回流一定发生了重绘
    知道上面的原理之后,对于开发过程有什么指导意义呢
  • 避免频繁使用 style,而是采用修改class的方式。
  • 使用createDocumentFragment进行批量的 DOM 操作。
  • 对于 resize、scroll 等进行防抖/节流处理。
  • 添加 will-change: tranform ,让渲染引擎为其单独实现一个图层,当这些变换发生时,仅仅只是利用合成线程去处理这些变换,而不牵扯到主线程,大大提高渲染效率。当然这个变化不限于tranform, 任何可以实现合成效果的 CSS 属性都能用will-change来声明。

防抖和节流

防抖:
短时间内大量触发同一事件,只会执行一次函数,实现原理为设置一个定时器,约定在xx毫秒后再触发事件处理,每次触发事件都会重新设置计时器,直到xx毫秒内无第二次操作,防抖常用于搜索框/滚动条的监听事件处理,如果不做防抖,每输入一个字/滚动屏幕,都会触发事件处理,造成性能浪费。

function debounce(fn, delay) {
  let timer = null;
  return function (...args) {
    let context = this;
    if(timer) clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, args);
    }, delay);
  }
}

节流:
防抖是延迟执行,而节流是间隔执行,函数节流即每隔一段时间就执行一次,实现原理为设置一个定时器,约定xx毫秒后执行事件,如果时间到了,那么执行函数并重置定时器,和防抖的区别在于,防抖每次触发事件都重置定时器,而节流在定时器到时间后再清空定时器

function throttle(fn, interval) {
  let flag = true;
  return funtion(...args) {
    let context = this;
    if (!flag) return;
    flag = false;
    setTimeout(() => {
      fn.apply(context, args);
      flag = true;
    }, interval);
  };
};

js的一些输出题

原型链

function A() {}
function B(a) {
    this.a = a;
}
function C(a) {
    if (a) {
        this.a = a;
    }
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;

console.log(new A().a);  //1,在原型中找到1
console.log(new B().a);  //自己有属性a,但是没有传值,所以是undefined
console.log(new C(2).a);  //2,有属性a且传值了,所以是2

数组与对象a[{}]

let a={},
    b='1',//'undefined'
    c=1;//undefined
a[b]='123';
a[c]='456';
console.log(a[b]); 
//结果为456,对象的属性名称唯一,且数字属性名和字符串属性名是一样的,
//对象的属性名称数据类型可以是布尔、null、undefined等等
//undefined结果也是456
let a={},
    b=Symbol('1'),
    c=Symbol('1');
a[b]='123';
a[c]='456';
console.log(a[b]);//结果为123,因为symbol创建的是唯一值
let a={},
    b={m:'1'},
    c={n:'2'};
a[b]='123';
a[c]='456';
console.log(a[b]);
//结果是456,对象的话都会由object.prototype.toString转换为字符串'object object',不管这个对象是啥

event loop

js循环机制:宏任务和微任务

  • 宏任务一般包括:整体代码script,setTimeout,setInterval。
  • 微任务:Promise,process.nextTick
    在这里插入图片描述
    首先主线的任务执行完,才会去事件队列中去找,事件队列中又先执行微任务,再宏任务
async function async1(){
    console.log("async1 start")
    await async2()
    console.log("async1 end")
}
async function async2(){
    console.log("async2")
}
console.log("script start")
setTimeout(function(){
    console.log("setTimeout")
},0)
async1();
new Promise(function(resolve){
    console.log("promise1")
    resolve()
}).then(function(){
    console.log("promise2")
})
console.log("script end")
//最终结果
//script start
//async1 start
//async2
//promise1
//script end
//async1 end
//promise2
//setTimeout

在这里插入图片描述

重写tostring,让a=1&&a=2&&a=3成立

//定义a,让下面成立,
//对象跟数字比首先会调用toString方法,这里相当于重写了toString方法,每次调用返回值都加1
var a={
    i:0,
    toString(){
        return ++this.i
    }
}
if(a==1 && a==2 && a==3){
    console.log('条件成立')
}

同名函数

function Foo() {
    getName = function () {
        document.write(1 + "第一个函数输出结果" + "<br/>")
    }
    return this
}
Foo.getName = function () {
    document.write(2 + "第二个函数输出结果" + "<br/>")
}
Foo.prototype.getName = function () {
    document.write(3 + "第三个函数输出结果" + "<br/>")
}
var getName = function () {
    document.write(4 + "第四个函数输出结果" + "<br/>")
}
function getName() {
    document.write(5 + "第五个函数输出结果" + "<br/>")
}
Foo.getName()  //2
getName()  //4
Foo().getName()  //1
getName() //1
new Foo.getName() //2
new Foo().getName() //3
new new Foo().getName() //3

在这里插入图片描述

this指向

var a=1;
function printA(){
  console.log(this.a);
}
var obj={
  a:2,
  foo:printA,
  bar:function(){
    printA();
  }
}

obj.foo(); //2
obj.bar(); //1
var foo=obj.foo;
foo(); //1

闭包

setTimeout循环输出

//因为setTimeout为宏任务,由于JS中单线程eventLoop机制,在主线程同步任务执行完后才去执行宏任务,
//因此循环结束后setTimeout中的回调才依次执行,但输出i的时候当前作用域没有,
//往上一级再找,发现了i,此时循环已经结束,i变成了6。因此会全部输出6

for(var i = 1; i <= 5; i ++){
  setTimeout(function timer(){
    console.log(i)
  }, 0)
}//输出5个6

如何解决
以下均输出1 2 3 4 5
//1.利用IIFE(立即执行函数表达式)当每次for循环时,把此时的i变量传递到定时器中

for(var i = 1;i <= 5;i++){
  (function(j){
    setTimeout(function timer(){
      console.log(j)
    }, 0)
  })(i)
}

//2.给定时器传入第三个参数, 作为timer函数的第一个函数参数

for(var i=1;i<=5;i++){
  setTimeout(function timer(j){
    console.log(j)
  }, 0, i)
}

//3.使用ES6中的let
//let使JS发生革命性的变化,让JS有函数作用域变为了块级作用域,用let后作用域链不复存在

for(let i = 1; i <= 5; i++){
  setTimeout(function timer(){
    console.log(i)
  },0)
}
闭包
var test=(function(i){
    return function(){
        console.log(i*=2)
    }
})(2); //到这相当于变量test被赋值为一个函数的返回值
test(5)
//结果还是4,i的值回去寻找上一级的i,跟5没啥关系,所以i不会被销毁,这就是闭包

//下面一段代码相当于定义了一个函数,并马上被执行了,参数i=2
//(function(i){
//    return function(){
//        console.log(i*=2)
 //   }
//})(2);
var a=0;
var b=0;
function A(a){
    A=function(b){
        console.log(a+b++)
    }
    console.log(a++)
}
A(1) //1
A(2) //4
//首先定义了两个全局变量a和b,还有一个函数A
//A(1):首先形参a赋值为1,然后在A函数里面函数A被重新赋值了(但是这个重新被复制的代码并没被执行)
//      然后执行打印a++,打印结果为1,但是此时形参a=2

js中数组、字符串、对象的常见方法

数组

arr.push(a):将a添加到数组的最后一项
arr.pop():删除数组的最后一项
arr.shift():删除原数组第一项,并返回删除元素的值;如果数组为空则返回undefined 。
arr.unshift(“a”,“b”):将参数a和b添加到原数组开头,并返回数组的长度 。
arr.sort():从小到大排序
arr.reverse():反转数组的顺序
arr.concat():将参数添加到原数组中,原数组并没有被修改
arr.slice():返回从原数组指定开始下标到结束下标之间的项组成的新数组
arr.splice():删除、插入和替换(改变原有的数组)
删除:指定 2 个参数:要删除的第一项的位置和要删除的项数。
 书写格式:arr.splice( 1 , 3 )
插入:可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、 0(要删除的项数)和要插入的项。
 书写格式:arr.splice( 2,0,4,6 )
替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。
 书写格式:arr.splice( 2,2,4,6 )
indexOf():接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的开头(位置 0)开始向后查找。
 书写格式:arr.indexof( 5 )
lastIndexOf:接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的末尾开始向前查找。
 书写格式:arr.lastIndexOf( 5,4 )
forEach():对数组进行遍历循环,对数组中的每一项运行给定函数。这个方法没有返回值。参数都是function类型,默认有传参,参数分别为:遍历的数组内容;第对应的数组索引,数组本身。
 书写格式:arr.forEach(function(x当前元素,index当前元素的index,arr当前元素所属的数组))
filter():“过滤”功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组。
every():判断数组中每一项都是否满足条件,只有所有项都满足条件,才会返回true。
some():判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。
 书写格式:arr.some()

字符串

slice(start,end)
substr(start,length)
substring(start,end)
charAt(pos)
concat(string…)
indexOf(searchString,position)/lastIndexOf(searchString,position)
localeCompare(that)
match(regexp)
replace(searchValue,replaceValue)

对象

在这里插入图片描述

跨域

jsonp

jsonp的原理:动态添加一个script标签,而script标签的src属性是没有跨域的限制的
jsonp的缺点

  • 只支持get,因为script标签只能使用get请求
  • jsonp在调用失败的时候不会返回各种http状态码
  • 安全性不太好
    优点就是可以跨域(利用script标签的src)兼容性比较好,而ajax会受到同源策略的影响,不允许进行跨域请求
    什么是跨域?
    同源策略是一种约定,协议+域名+端口三者相同,叫同源
    浏览器遵循同源政策(scheme(协议)、host(主机)和port(端口)都相同则为同源)。非同源站点有这样一些限制:
  • 不能读取和修改对方的 DOM
  • 不读访问对方的 Cookie、IndexDB 和 LocalStorage
  • 限制 XMLHttpRequest 请求。(后面的话题着重围绕这个)
  • 当浏览器向目标 URI 发 Ajax 请求时,只要当前 URL 和目标 URL 不同源,则产生跨域,被称为跨域请求。

如何实现跨域?

  • jsonp实现跨域
  • Nginx
    Nginx 是一种高性能的反向代理服务器,可以用来轻松解决跨域问题
    正向代理帮助客户端访问客户端自己访问不到的服务器,然后将结果返回给客户端。
    反向代理拿到客户端的请求,将请求转发给其他的服务器,主要的场景是维持服务器集群的负载均衡,换句话说,反向代理帮其它的服务器拿到请求,然后选择一个合适的服务器,将请求转交给它。
    因此,两者的区别就很明显了,正向代理服务器是帮客户端做事情,而反向代理服务器是帮其它的服务器做事情。
  • 使用iframe+window.name/window.postMessage等等来进行跨域
    (window.name来进行跨域,window对象有个name属性,该属性有个特征:在一个窗口的生命周期内,窗口载入的所有页面都是共享一个window.name的,每个页面都有读写的权限,window.name是持久存在的一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置使用window.postMessage方法(html新特性):可以使用它来向其他的window对象发送消息,调用PostMessage方法的window对象时指要接收消息的那个window对象,该方法的第一个参数message为要发送的消息,类型只能是字符串,第二个参数targetOrigin用来限定接收消息的那个window对象所在域,如果不想限定域,可以使用通配符*)
  • cors跨域(对浏览只是支持ie10,不仅可以使用get请求,还有其他的)
    整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
    因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
    浏览器将CORS请求分成两类:简单请求和非简单请求。
    在这里插入图片描述

简单请求
它会自动在请求头当中,添加一个Origin字段,用来说明请求来自哪个源。服务器拿到请求之后,在回应时对应地添加Access-Control-Allow-Origin字段,如果Origin不在这个字段的范围中,那么浏览器就会将响应拦截。
因此,Access-Control-Allow-Origin字段是服务器用来决定浏览器是否拦截这个响应,这是必需的字段。与此同时,其它一些可选的功能性的字段,用来描述如果不会拦截,这些字段将会发挥各自的作用。
Access-Control-Allow-Credentials。这个字段是一个布尔值,表示是否允许发送 Cookie,对于跨域请求,浏览器对这个字段默认值设为 false,而如果需要拿到浏览器的 Cookie,需要添加这个响应头并设为true, 并且在前端也需要设置withCredentials属性。
Access-Control-Expose-Headers。这个字段是给 XMLHttpRequest(XMLHttpRequest.getResponseHeader拿到字段) 对象赋值,让它不仅可以拿到基本的 6 个响应头字段(包括Cache-Control、Content-Language、Content-Type、Expires、Last-Modified和Pragma), 还能拿到这个字段声明的响应头字段。
非简单请求:
非简单请求相对而言会有些不同,体现在两个方面: 预检请求和响应字段
预检请求的方法是OPTIONS,同时会加上Origin源地址和Host目标地址,同时也会加上两个关键的字段:
Access-Control-Request-Method, 列出 CORS 请求用到哪个HTTP方法
Access-Control-Request-Headers,指定 CORS 请求将要加上什么请求头
响应字段:
其中有这样几个关键的响应头字段:
Access-Control-Allow-Origin: 表示可以允许请求的源,可以填具体的源名,也可以填*表示允许任意源请求。
Access-Control-Allow-Methods: 表示允许的请求方法列表。
Access-Control-Allow-Credentials: 简单请求中已经介绍。
Access-Control-Allow-Headers: 表示允许发送的请求头字段
Access-Control-Max-Age: 预检请求的有效期,在此期间,不用发出另外一条预检请求。
在预检请求的响应返回后,如果请求不满足响应头的条件,则触发XMLHttpRequest的onerror方法,当然后面真正的CORS请求也不会发出去了。
CORS 请求的响应。绕了这么一大转,**到了真正的 CORS 请求就容易多了,现在它和简单请求的情况是一样的。浏览器自动加上Origin字段,服务端响应头返回Access-Control-Allow-Origin。**可以参考以上简单请求部分的内容。

ajax:

ajax是异步的JavaScript和xml,在无需重新加载整个网页的情况下,能够与服务器交换数据并更新部分网页
XMLHttpRequest是ajax的基础,用于和服务器交换数据

//创建XMLHttpRequest对象
var xmlHttp=new XMLHttpRequest()

向服务器发送请求,使用open()和send()方法

//open的三个参数,第一个请求类型,第二个请求的url,第三个异步(true)还是同步
//send也有一个参数string,参数是发送的数据,但是只有在post请求才能用,post请求还需要添加请求头
xmlHttp.open("Get","url",true)
xmlHttp.send()

获取服务器响应,使用responseText或responseXML属性

document.getElementById("myDiv").innerHTML=xmlhttp.responseText;

XMLHttpRequest有三个重要的属性

  • onreadystatechange:当readyState属性改变时,就会调用该函数
  • readyState:XMLHttpRequest的状态
    0:请求未初始化,还没有调用open方法
    1:服务器连接已建立,但是还没发送,还没调用send方法
    2:请求已接受
    3:请求处理中
    4:请求已完成,且响应已就绪
  • status:状态,200,404等等
    当readyState=4且status=200时,表示响应已就绪

实现一个ajax

创建XMLHttpRequest对象、open与服务器创建连接,send发送数据、针对返回的不同的响应状态进行处理

  • 创建XMLHttpRequest对象
var xhr = new XMLHttpRequest()
  • 设置回调函数
xhr.onreadystatechange = callback
  • 使用open方法与服务器建立连接
// get 方式
xhr.open("get", "test.php", true)

// post 方式发送数据 需要设置请求头
xhr.open("post", "test.php", true) //true表示异步,false表示同步
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
  • 向服务器发送数据
// get 不需要传递参数
xhr.send()

// post 需要传递参数
xhr.send("name=jay&age=18")
  • 在回调函数中针对不同的响应状态进行处理
function callback() {
  // 判断异步对象的状态
  if(xhr.readyState == 4) {
    // 判断交互是否成功
    if(xhr.status == 200) {
      // 获取服务器响应的数据
      var res = xhr.responseText
      // 解析数据
      res = JSON.parse(res)
    }
  }
}

axios

在这里插入图片描述

写一个axios请求

axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

// 可选地,上面的请求可以这样做
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  
  
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });  

diff算法

虚拟dom中采用的算法,只更新我们修改的那一小块dom而不是更新整个dom(直接到真实的dom上去渲染会更新整个dom树的渲染)
首先根据真实的dom生成一颗虚拟dom,当虚拟dom某个节点的数据改变后会生成一个新的虚拟节点,然后虚拟节点和旧的节点比较,发现有不一样的地方就直接修改在真实的dom上,然后使旧的节点值为虚拟节点的值
在这里插入图片描述
diff的过程就是调用patch的函数,比较新旧节点,一边比较一边给真实的dom打补丁
diff比较新旧节点的时候,只会在同层级进行比较,不会跨层级比较
两棵树完全的diff算法时间复杂度是O(n3),vue转换成了O(n),只比较同级不考虑跨级
patch(oldVnode,vnode):首先判断是否值得比较(是不是同一个元素),值得比较就执行patchVnode,不值得比较就直接用Vnode替换oldVnode
如果两个节点是一样的,那么就深入的检查他们的子节点,根据不同的情况做出处理
在这里插入图片描述

v-for为什么要加key

加上key可以减少性能消耗,更高效的更新虚拟dom。vue是用的diff算法,diff源码中有一个判断是否是同一个元素的sameVnode函数,标准是key相同且tag相同,如果不加key,默认所有的节点的key都是相同的,就会按照就地复用来进行比较(当旧的节点有abcd,而新的节点只有bcd,那a就会复用b的结构)

为什么不用index作为key?

表面上没有什么问题,都是有两点不足:
1.index作为key,其实就等于不加key
2.index作为key,只适用于不依赖子组件状态或临时dom状态(表单输入值)的列表渲染输出
因为不管你数组的顺序怎么颠倒,index 都是 0, 1, 2 这样排列,导致 Vue 会复用错误的旧子节点,做很多额外的工作。

webpack

**打包原理:**把所有依赖打包成一个bundle.js文件,通过代码分割成单元片段并按需加载。

bundle是由webpack打包出来的文件,chunk是指webpack在进行模块的依赖分析的时候,代码分割出来的代码块。module是开发中的单个模块。
webpack与grunt、gulp的不同?
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。

  • grunt和gulp是基于任务和流(Task、Stream)的。需要开发者将整个前端构建过程拆分成多个Task,会找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
  • webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。

Loader和Plugin?

不同的作用
Loader直译为"加载器"。webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
不同的用法
Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。

有哪些常见的Loader?他们是解决什么问题的?

  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
  • url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
  • source-map-loader:加载额外的 Source Map 文件,以方便断点调试
  • image-loader:加载并且压缩图片文件
  • babel-loader:把 ES6 转换成 ES5
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
  • style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
  • eslint-loader:通过 ESLint 检查 JavaScript 代码
    有哪些常见的Plugin?他们是解决什么问题的?
  • define-plugin:定义环境变量
  • commons-chunk-plugin:提取公共代码
  • uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码

webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  • 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
  • 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
  • 确定入口:根据配置中的 entry 找出所有的入口文件;
  • 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
  • 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
    在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

webpack的热更新

webpack的热更新又称热替换。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。

如何利用webpack来优化前端性能?(提高性能和体验)

  • 用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
  • 压缩代码。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css
  • 利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output参数和各loader的publicPath参数来修改资源路径
  • 删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数–optimize-minimize来实现
    提取公共代码。

如何提高webpack的构建速度?

  • 多入口情况下,使用CommonsChunkPlugin来提取公共代码
  • 通过externals配置来提取常用库
  • 利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
  • 使用Happypack 实现多线程加速编译
  • 使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度
    使用Tree-shaking和Scope Hoisting来剔除多余代码

怎么配置单页应用?怎么配置多页应用?

单页应用可以理解为webpack的标准模式,直接在entry中指定单页应用的入口即可
多页应用的话,可以使用webpack的 AutoWebPlugin来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。 多页应用中要注意的是
每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了同一套css样式表
随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加新页面还需要修改构建配置

对于webpack配置做以下扩展和优化:

  • CommonJS模块化规范的解决方案: 设置output.libraryTarget='commonjs2’使输出的代码符合CommonJS2 模块化规范,以供给其它模块导入使用
  • 输出ES5代码的解决方案:使用babel-loader把 ES6 代码转换成 ES5 的代码。再通过开启devtool: 'source-map’输出SourceMap以发布调试。
  • Npm包大小尽量小的解决方案:Babel 在把 ES6 代码转换成 ES5 代码时会注入一些辅助函数,最终导致每个输出的文件中都包含这段辅助函数的代码,造成了代码的冗余。解决方法是修改.babelrc文件,为其加入transform-runtime插件
  • 不能将依赖模块打包到NPM模块中的解决方案:使用externals配置项来告诉webpack哪些模块不需要打包。
  • 对于依赖的资源文件打包的解决方案:通过css-loader和extract-text-webpack-plugin来实现

如何在vue项目中实现按需加载?

很多组件库已经提供了现成的解决方案,如Element出品的babel-plugin-component和AntDesign出品的babel-plugin-import 安装以上插件后,在.babelrc配置中或babel-loader的参数中进行设置,即可实现组件按需加载了。

common.js

CommonJS(node.js、webpack)是一种被广泛使用的js模块化规范,核心思想是通过require方法来同步加载依赖的其他模块,通过module.exports导出需要暴露的接口。

//导入 
const moduleA = require (. / moduleA’); 
//导出 
module .exports = moduleA.someFunc; 

commo.js和AMD

common.js用于服务器,AMD用于浏览器
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module], callback);
第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。

common.js与es6的模块化的区别:

两者的模块导入导出语法不同,commonjs是module.exports,exports导出,require导入;ES6则是export导出,import导入。
commonjs是运行时加载模块,ES6是在静态编译期间就确定模块的依赖。(之后就说只了解这么多)

restful

与技术无关,代表的是一种软件架构风格
在http协议中,四个表示操作方式的动词:GET/Post/put/Delete,他们分别对应四种基本操作。
Get用来获取资源。post用来新建立资源,也可以更新资源。put用来更新资源。Delete用来删除资源。
还有一些状态码,url尽量使用一看就知道意思的取名

对软件工程的理解

软件工程就是按照工程学的管理方式,有组织、有计划的,在一定的质量基础、时间限度和成本范围内,实现功能明确的软件系统。几个阶段
在这里插入图片描述

vue

对于MVVM的理解

是model-view-viewmodel的缩写

  • model代表数据模型
  • view代表ui组件,负责将数据模型转化成ui展现出来
  • viewmodel:ViewModel负责把Model的数据同步到view显出来,还负责把view修改同步到Model。

model和view之间并没有直接的联系,而是通过viewmodel进行交互,model和viewmodel之间的交互是双向的,因此view数据的变化会同步到model中,而model中数据变化也会立即反应到view中

mvc和mvvm的区别:

mvc:用户对View的操作交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操作,一旦Model发生变化便通知相关视图进行更新。
mvvm:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变。

MVC有两个很明显的问题:
1.m层和v层直接打交道,导致这两层耦合度高
2.因为所有逻辑都写在c层,导致c层特别臃肿
为了解决这两个问题,MVC的变种模式出现了MVVM.

vue的生命周期

vue实例都有一个完整的生命周期,初始化、运行到结束。
创建期间的生命周期函数:

  • beforeCreate:实例刚被创建出来,还没初始化好data和method,一般不做操作
  • created:实例已经在内存中创建OK,可以访问data和method,还没编译模板常用于页面初始化(数据最早在created中访问到)
  • beforeMount:完成模板编译,(只是虚拟的dom)但是还没有挂载到页面中
  • mounted:已经将编译好的模板挂载到了页面(真实的dom)中
    运行期间的生命周期函数:($ref属性在这可以访问到)
  • beforeUpdate:状态更新之前执行该函数,此时data中的数据是最新的,但是页面上的还是旧的
  • updated:实例更新完毕之后调用此函数,data和页面上的数据都是最新的
    销毁期间的生命周期函数:
  • beforeDestroy:实例销毁之前调用
  • destroy:实例销毁之后调用

组件通信

详情
在这里插入图片描述

  • 属性传递:只能父组件传子组件,子不能传/改父
  • $emit触发自定义事件,实现子向父传值
  • 事件总线(EventBus):新建一个Vue事件bus对象,然后通过bus. e m i t 触 发 事 件 , b u s . emit触发事件,bus. emitbus.on监听触发的事件。
  • provide/inject
    在这里插入图片描述
  • p a r e n t / parent/ parent/children
    利用 c h i l d r e n 可 以 直 接 获 取 子 组 件 的 实 例 , 利 用 children可以直接获取子组件的实例,利用 childrenparent则可以直接获取到父组件的实例
  • vuex、localstorage
    如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护
    vuex(创建一个store的文件夹)的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。
    在这里插入图片描述

$set原理

在这里插入图片描述

template模板渲染语法和原理

1.把模板编译为render函数
2.根据根节点render函数的调用,递归的生成虚拟dom
3.通过diff算法对比虚拟dom,渲染到真实dom(类同react的虚拟DOM渲染过程)

指令和自定义指令

指令有v-bind,v-model(一些表单控件input数据的双向绑定),v-if,v-show,v-for等等
通过vue.directive来自定义
代码详情
vue.directive(‘参数名称’,{这里面可以写钩子函数}) 定义指令,它有两个参数
-参数1:指令名称,注意在定义的时候,指令名称前不需要加 v- 前缀,但是在调用的时候,必须加v- 前缀。
参数2:参数2是一个对象,这个对象身上有一些指令相关的函数(也就是下边介绍的钩子函数),这些函数可以在特定的阶段,执行相关操作。

钩子函数:

  • bind :只调用一次,每当指令绑定到元素上的时候,还没有插入到dom中,会立即执行这个 bind 函数。(一般和样式操作有关的,一般都可以在 bind 函数中执行)
  • inserted : 表示元素 插入到DOM中的时候,会执行 inserted 函数,触发一次。(例如:自动获取焦点)
  • updated : 当VNode 更新的时候,会执行 updated 函数,可能会触发多次
  • componentUpdated : 指令所在组件的VNode 及其子 VNode 全部更新后调用。
  • upbind: 只调用一次,指令与元素解绑时调用。

ref/如何获取dom

操纵dom的一个属性,在标签中定义ref=“xxx”,用this.$refs.xxx来调用

插槽

子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码

用法:(具名插槽)可以在slot中写上name=“xxx”,然后父组件中插入的内容中用v-slot绑定对应的name值,还有默认插槽,就是没有名字的插槽
作用域插槽就是一般需要传递参数数据,子组件slot中通过:data="data"来绑定数据,然后在父组件中用slot-scope来获取子组件中的数据

双向数据绑定的实现原理:

在这里插入图片描述

双向数据绑定就是让数据层和视图层中的数据同步,在写入数据时视图层实时的跟着更新

  • vue2.0:通过数据劫持和发布-订阅者功能来实现的,在object.defineproperty()中重新定义get和set方法
    实现步骤:
    1.实现一个监听者Oberver来劫持并监听所有的属性,一旦有属性发生变化就通知订阅者
    2.实现一个订阅者watcher来接受属性变化的通知并执行相应的方法,从而更新视图
    3.实现一个解析器compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相对应的订阅者
  • vue3.0:使用proxy代理中直接定义get和set方法
    在这里插入图片描述
    在这里插入图片描述

截器的作用

在这里插入图片描述

路由实现

在这里插入图片描述

路由传参的两种方式

params和query
区别:query要用path来引入,params要用name来引入,接收参数都是类似的;query更加类似于get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
在这里插入图片描述
在这里插入图片描述

v-if和v-show

在这里插入图片描述

vue的优点

在这里插入图片描述

computed和watched的区

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

浏览器安全

XSS攻击

XSS 攻击是指浏览器中执行恶意脚本(无论是跨域还是同域),从而拿到用户的信息并进行操作。
这些操作一般可以完成下面这些事情:

  • 窃取Cookie。
  • 监听用户行为,比如输入账号密码后直接发送到黑客服务器。
  • 修改 DOM 伪造登录表单。
  • 在页面中生成浮窗广告。
    通常情况,XSS 攻击的实现有三种方式——存储型、反射型和文档型
  • 存储型:将恶意脚本存储了起来,常见的场景是留言评论区提交一段脚本代码,如果前后端没有做好转义的工作,那评论内容存到了数据库,在页面渲染过程中直接执行, 相当于执行一段未知逻辑的 JS 代码,是非常恐怖的。这就是存储型的 XSS 攻击。
  • 反射型:恶意脚本作为网络请求的一部分。恶意脚本是通过作为网络请求的参数,经过服务器,然后再反射到HTML文档中,执行解析。
  • 文档型:文档型的 XSS 攻击并不会经过服务端,而是作为中间人的角色,在数据传输过程劫持到网络数据包,然后修改里面的 html 文档!

怎么防止XSS攻击?

  • 对输入内容转码或者过滤,让其不可执行
  • CSP,即浏览器中的内容安全策略,它的核心思想就是服务器决定浏览器加载哪些资源
  • 利用 Cookie 的 HttpOnly 属性,JavaScript 便无法读取 Cookie 的值

CSRF攻击

CSRF(Cross-site request forgery), 即跨站请求伪造,指的是黑客诱导用户点击链接,打开黑客的网站,然后黑客利用用户目前的登录状态发起跨站请求。
CSRF攻击一般会有三种方式:

  • 自动 GET 请求
  • 自动 POST 请求
  • 诱导点击发送 GET 请求。

怎么防止CSRF攻击

  1. 利用Cookie的SameSite属性
    SameSite可以设置为三个值,Strict、Lax和None。
    a. 在Strict模式下,浏览器完全禁止第三方请求携带Cookie。比如请求sanyuan.com网站只能在sanyuan.com域名当中请求才能携带 Cookie,在其他网站请求都不能。
    b. 在Lax模式,就宽松一点了,但是只能在 get 方法提交表单况或者a 标签发送 get 请求的情况下可以携带 Cookie,其他情况均不能。
    c. 在None模式下,也就是默认模式,请求会自动携带上 Cookie。
    2.验证来源站点
    这就需要要用到请求头中的两个字段: Origin和Referer。
    其中,Origin只包含域名信息,而Referer包含了具体的 URL 路径。
    当然,这两者都是可以伪造的,通过 Ajax 中自定义请求头即可,安全性略差。
    3.CSRF Token,浏览器向服务器发送请求时,服务器生成一个字符串,将其植入到返回的页面中。
    然后浏览器如果要发送请求,就必须带上这个字符串,然后服务器来验证是否合法,如果不合法则不予响应。这个字符串也就是CSRF Token,通常第三方站点无法拿到这个 token, 因此也就是被服务器给拒绝。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值