–前端面试知识总结
1.http/浏览器部分
1.1 http和https
概念
- http:超文本传输协议,是一种客户端和服务端请求应答的标准,用于从www服务端传输超文本到本地浏览器的传输协议。
- https:以安全为目标的http,在http下又加上了SSL层,确保数据的传输和网站的真实性。
区别:
- http是超文本传输协议,信息是明文传输的,没有加密。https是具有安全性的ssl加密传输协议。
- http协议的端口是80,https是443
- http的连接很简单,是无状态的;https协议是由ssl+http协议构建的可进行加密传输、身份认证的网络协议,更加安全。
- https协议需要ca证书,费用高。
https工作原理:
- 客户端向服务端请求https连接,要求与服务器建立ssl连接
- 服务端收到请求,将网站的证书包含公钥传给客户端
- 客户端收到证书先检查证书的颁发机构和过期时间,确认无误之后产生随机的密钥
- 客户端使用公钥将密钥加密传给服务端。服务端利用自己的私钥解密出会话密钥。
- 服务端和客户端开始使用密钥通信
这个过程中,会出现中间人攻击,就是第一次服务器向客户端返回公钥的时候,在中间被攻击者截获,生成【伪公钥】给了客户端,之后客户端生成的秘钥发送给服务器时,在中间又被攻击者截获,攻击者就可以通过自己的私钥获得真的秘钥,然后又伪造假的秘钥给服务器,这样客户端和服务器端的通信就完全暴露给攻击者了,因为双方的加密过程都被攻击者知道的一清二楚;所以第一次服务器给客户端返回公钥时,必须一同返回CA证书。
1.2 五层协议
- 应用层:应用进程之间的通信与交互规则;直接为用户的应用进程提供服务。比如支持万维网的HTTP协议,支持邮件的SMTP服务,支持文件传输的FTP
- 运输层:负责向两个主机中进程之间的通信提供服务。分为TCP和UDP两种协议。
- 网络层:任务一,负责为分组交换网上的不同主机提供通信服务,一般是将运输层的报文段或者用户数据封装成分组或包进行传送。任务二,选中合适的路由,使源主机运输层传下来的分组能够通过路由器找到目的主机。 协议:IP,ICMP,IGMP,ARP,RARP
- 链路层:将网络层传下来的ip数据报封装成帧,在两个相邻结点链路上(点对点),‘透明’传送帧上的数据。每帧上包括数据信息和控制信息(差错控制,同步信息,地址信息等)
- 物理层:利用物理媒体(电缆等)传送比特流。
1.3 ARP/ICMP协议
- ARP( Address Resolution Protocol )地址解析协议:知道ip地址,找到其对应的硬件地址。通过ARP高速缓存,找到本局域网各主机ip到硬件地址的映射表。
- ICMP( Internet Control Messages Protocol )网际控制报文协议:允许主机或路由器报告差错和异常情况。
1.4 TCP/UDP
- TCP(Transmission Control Protocol)传输控制协议:面向连接的,数据传输的单位是报文段,能够提供可靠的交付;
- UDP(User Datagram Protocol)用户数据报协议:无连接,数据传输的单位是用户数据报,不保证提供可靠的交付,是“尽最大努力交付”。
比较:
- 可靠性:TCP面向连接可靠性高;UDP无连接可靠性低;
- 复杂度:TCP需要三次握手,重新确认等待连接的过程,过程更加复杂,实时性差;UDP没有建立连接的过程,简单且实时性较强。
- 首部开销:传输相同大小的数据时,TCP首部开销20字节,UDP首部开销8字节,且TCP报头更加复杂,所能包含的用户数据较少。故TCP开销大。
- 通信方式:TCP是点到点的;UDP支持一对一,一对多,多对一,多对多的交互通信。
应用场景:
- 对实时性要求高和高速传输的场合使用UDP;在对可靠性要求低,追求效率情况下使用UDP.
- 传输大量数据且对可靠性要求高时使用TCP。
1.5 TCP三次握手和四次挥手
三次握手: 客户端和服务端都需要直到各自可收发
- 客户端向服务器端发送请求
- 服务器端收到请求之后,若同意通信,向客户端发送确认,且告知自己可以收到报文
- 客户端收到服务器端的ACK,再发送确认的确认。
第三次握手是为了防止失效的连接请求又传送到了服务器建立了连接,浪费网络资源
四次挥手
- 客户端首先发送连接释放请求
- 服务器收到后发出确认(此时客户机不能向服务器发送数据,但服务器还可以向客户端发送数据,tcp处于半关闭状态)。客户端收到确认之后,进入等待中。
- 服务器数据发完,向客户端发送释放连接请求
- 客户端收到关闭连接请求,发送确认。客户端等待2MSL(四分钟,最长报文段寿命)之后关闭连接。
等待2MSL:保证客户端最后一个确认的报文可以到达服务器, 保证tcp连接能够进行可靠的关闭 (假如客户端发送ack之后直接关闭了,然后ack又丢失了,服务器端就会一直处于等待关闭的状态,等待一定时间后会重复向客户端发送释放连接请求,但是客户端已经关闭了)
且防止已经失效的连接请求出现在连接中( 客户端在发送最后一个ACK之后,再经过经过2MSL,就可以使本链接持续时间内所产生的所有报文段都从网络中消失。从保证在关闭连接后不会有还在网络中滞留的报文段去骚扰服务器 )。
2MSL: Maximum Segment Life,这是TCP 对TCP Segment 生存时间的限制 : 客户端发出ACK,等待ACK到达对方的超时时间 MSL,等待FIN的超时重传,也是MSL,所以如果2MSL时间内没有收到FIN,说明对方安全收到FIN
总结:建立连接:服务器要确认客户端的连接请求,客户端对服务器的确认进行确认。
1.6 页面输入url到页面加载完成
- DNS解析获取IP地址
- 建立TCP连接(三次握手)
- 发送HTTP请求
- 服务器处理请求并返回HTTP报文
- 浏览器构建DOM和CSSOM形成渲染树,渲染页面
- 关闭TCP连接(四次挥手)
https://www.cnblogs.com/daijinxue/p/6640153.html
1.7 TCP计时器
-
重传计时器:
tcp发送报文时候启动重传计时器,在计时器截止时间之前收到了对这个发送的报文的ack,就撤销计时器;
在时间到之后还没收到ack,就重传报文,并将计时器复位,重新开始计时。
-
持久计时器:
当发送tcp收到窗口大小为0的确认时,就启动持久计时器,时间到了之后,会发送特殊的探测报文,收不到探测报文的确认之后就会将持久计时器复位且时间加倍,之后时间到了继续发送探测报文… …直到计时器时间到达60s,之后计时器时间不会再加倍,发送端就会60s发送一次探测报文,直到接受端确认可以发送数据了(窗口大于0了)。
-
保活计时器:
防止两个TCP之间出现长时间的空闲。
一般是服务器收到客户端的信息之后就会在服务器上设置保活计时器(2h)。
比如,客户端故障了,服务器收不到客户端的信息,等待2h之后,就会发送探测报文(每75s发送一个),发送10个之后还没有响应,就直接判定客户端故障,断开连接。(硬性中断)。
-
时间等待计时器:四次挥手中的2MSL.
1.8 post/get区别
post和get本质上没有任何区别,都是http协议中的请求方法,本质都是tcp连接;
为了对不同请求的类型做出区分,才有了getpostdeleteput这几种,然后制定了一些使用上的规定:
- get请求一般是用于信息获取,使用url传递参数,对于发送的信息长度有限制,一般为2k;请求的参数只能是ASCII码/url编码。
- post请求i一般用来修改服务器上的资源,对请求长度没有限制,请求的参数也没有编码限制
- get请求的参数是放在url里的,post是放在i请求体里。
- get请求浏览器将http header data一起发送到服务器,之后返回200和数据,产生一个tcp数据包
- post,浏览器先发送header,服务器响应100,在发送data,服务器响应200和返回的数据,产生两个tcp数据包。
应用场景:
-
post :
无法使用缓存文件,要更新服务器上的文件或者数据库时
发送大量数据时
发送包含未知字符的数据时
1.9 cookie和session
- cookie: 存储在客户端的数据。 并随每个请求发送到同一服务器 , 这样服务器就能从cookie接收到的信息里识别你的身份,让页面为你提供特别属于你的内容。
- session: 存储在服务器端的信息,可用来跟踪用户的整个会话。 客户端浏览器访问网站的时候 , 服务器会向客户浏览器发送一个每个用户特有的会话编号sessionID,让他进入到cookie里。 服务器同时也把sessionID和对应的用户信息、用户操作记录在服务器上,这些记录就是session。 客户端浏览器再次访问时,会发送cookie给服务器,其中就包含sessionID。 服务器从cookie里找到sessionID,再根据sessionID找到以前记录的用户信息就可以知道他之前操控些、访问过哪里。
session比cookie安全可靠些,且可存储的数据量无限制(cookie只允许4k),但是session中信息过多开销很大。
1.10 HTTP状态码
-
1XX:信息类状态码,表示信息正在处理。
100 continue:到目前为止正常,客户端可以继续发送请求。post请求第一次tcpl连接就是返回100.
-
2XX:成功类,表示请求处理成功。
200 ok : 请求成功。用于post/get请求
-
3XX:重定向状态码,需要进一步操作完成请求。
301:永久重定向
302:临时重定向
303:使用get方法临时重定向
304:如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。自从上次请求后,请求的网页未修改过。
305:临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。
-
4XX:客户端错误,表示客户端请求出错或无法完成请求
400 Bad Request:请求报文中存在语法错误, 前端提交数据的字段名称和字段类型与后台的实体没有保持一致 (常见的就是后台要求接收json字符串,但是前端没有处理好)
401:发送的请求需要有认证信息
403 Forbidden:请求被拒绝
404 Not Found:服务器无法根据客户端的请求找到资源
-
5XX:服务器错误,服务器在处理请求过程中发生了错误
500 Internal Server Error:服务器内部错误
503 Service Unavailable:由于超载或系统维护,服务器暂时无法处理客户端请求
1.11 HTTP报文结构
HTTP报文是用于HTTP协议交互的信息,本身是多行数据构成的字符串文本;可以分为请求报文和响应报文。
-
请求报文
请求行:请求方法,url,HTTP版本
请求首部字段,通用首部字段,实体首部字段
请求内容实体
-
响应报文
状态行:HTTP版本,状态码
响应首部字段,通用首部字段,实体首部字段
响应内容实体
1.12 常见HTTP首部字段
-
请求首部字段
Host:请求资源所在服务器
Accept:可接受的媒体类型
Accept-Charset:可接受的字符集
Accept-Encoding:可接受的内容编码
Accept-Language:可接受的自然语言
-
响应首部字段
Accept-Ranges:可接受的字节范围
Location:令客户端重定向到的url
Server:HTTP服务器的安装信息
-
通用首部字段
Date:创建报文的时间
Connection:连接管理
Cache-Control:缓存控制
Transfer-Encoding:报文主体的传输编码方式
-
实体首部字段
Allow:资源可支持的HTTP方法
Content-Type:实体主体适用的编码方式
Content-Language:实体主体的自然语言
Content-Length:实体主体的字节数
Content-Range:实体主体的位置范文,一般是发出请求时使用
1.13 HTTP1.0/1.1/2.0区别
-
http 1.0
-
特点
无状态:服务器不跟踪不记录请求的过程
无连接:浏览器每次请求都要建立tcpl连接
-
缺点
无法复用请求:每次发起请求都要进行tcp连接,网络利用率低
队头阻塞:在前一个请求响应到达之后才能发起新的请求。请求1 > 响应1 请求2 > 响应2 请求3 > 响应3
-
-
http 1.1
-
特点
长连接:新增Connection字段设置keep-alive保持tcp连接不断开,继续使用这个通道传输数据
管道化:请求可以不等响应,继续发送;请求1 --> 请求2 --> 请求3 > 响应1 --> 响应2 --> 响应3
缓存处理:新增Cache-Control,请求资源时如果有缓存就直接取,没有缓存再发送请求
断点传输:上传下载时,可以从断点处开始
-
缺点
管道化中虽然请求可以持续发送,但是人不能解决队头阻塞。
-
-
http 2.0
-
特点
二进制分帧:对所有传输的信息使用二进制编码,分割成更小的消息和帧。解决了数据过多和串行传输问题。
多路复用:同时发送请求和接受响应。同一个连接并发处理多个请求
头部压缩:压缩header,体积更小,传输更快
服务器推送:服务器可额外向客户端推送资源,适合加载静态资源。
http 1.0 —> http 1.1 长连接
http 1.1 —> http 2.0 多路复用
-
1.14 代理
代理ip就是代理服务器,是一种重要的安全功能,主要在开放系统互联模型的会话层起到防火墙的作用。分为正向代理和反向代理,一把直接说代理是指正向代理。
-
正向代理
正向代理介于用户和目标服务器之间,客户端向代理发起请求,代理将请求转发给目标服务器,然后将目标服务器响应返回给客户端。
-
反向代理
反向代理也是处于客户端和目标服务器之间,负责转发请求和响应的。但是客户端是不知代理存在情况下,直接访问目标服务器站点。
总结:一个是用户向代理服务器发起请求,一个是用户向目标服务器发起请求。虽然都是由代理进行转发,但是从用户的角度是不一样的,正向中用户知道代理的存在,但是反向中用户不知代理的存在。
1.15 nginx和负载均衡
ngnix是一个高性能的http服务器和反向代理web服务器
将代理服务器接收到的请求按照规则分发的过程,称为负载均衡。(负载指反向代理接收到的请求数量)
1.16 前端实现即时通信
-
短轮询
客户端使用定时器向服务器发送Ajax请求
浪费带宽和服务器资源
-
长轮询
客户端向服务器发送请求,只有当数据符合要求时才会响应(如果超时没有响应,就关闭连接),客户端收到响应或连接关闭后,可再次发起新的请求
服务器维护长连接增加开销
-
长连接
页面中插入iframe或script向服务器发起请求(减少对主页面的影响)
服务器维护长连接增加开销,iframe可能涉及跨域。
-
WebSocket
是HTML5开始提供的一种在单个tcp连接上进行全双工通讯的协议。
特点:
- 上三种都是客户端主动发起请求,是单向通信,但是WebSocket是服务器和客户端后可以主动向对方发起响应,服务器可以实现推送功能。
- 与http协议有良好的兼容性
- 数据格式轻量,性能开销小,通信高效。
- 没有同源限制,不涉及跨域
function myWebSocket(){ if('WebSocket' in window){ //ws指http wss指https let ws = new WebSocket('ws://localhost:3000'); //连接建立时触发 ws.onopen = () => { ws.send('data'); } //客户端收到服务器数据时触发 ws.onmessage = (e) => { console.log(e.data) } //通信发生错误时触发 ws.error = (e) => { console.log(e) } //连接关闭时触发 ws.onclose = () => { console.log('ws close') } } else{ console.log('浏览器不支持websocket') } }
2.攻击技术
2.1 跨站脚本攻击
利用用户对指定网站的信任
- 跨站脚本攻击:Cross-Site Scripting, XSS,是指攻击者在web页面中插入恶意脚本(html+js)。当用户浏览页面时执行脚本从而获取储存在客户端的cookie,达到攻击目的。
- 解决办法:不随意输入,设置cookie为httponly,使js脚本无法读取cookie信息。
2.2 跨站请求伪造
利用网站对浏览器的信任
- 跨站请求伪造:Cross-site request forgery,CSRF,攻击者盗用用户身份,以用户身份发起恶意请求。一般是因为本地cookie存有用户信息,访问危险网站的时候浏览器会以为这是本人访问的。
- 解决办法:后台要求请求必须携带token,或者使用验证码
2.3 SQL注入攻击
- 指攻击者向服务器提交恶意的sql语句,在服务器上运行非法的sql语句,主要通过拼接完成,目的是获取数据库中的一些数据或者使得用户查询出错
- 解决办法:使用预编译语句或者转义特殊字符进行预防,多使用存储过程和视图。
2.4 拒绝服务攻击
- 拒绝服务攻击(DOS):亦称洪水攻击,通过发送大量请求使服务器瘫痪。目的是使目标电脑的网络或者系统资源耗尽,使服务暂时中断,导致用户无法访问。
- 分布式拒绝服务攻击(DDOS):攻击者使用两个以上的电脑发动DOS
- 解决办法:检测技术 清洗技术
3.html/css部分
3.1 html
- html:超文本标记语言,是一种标识性地语言,不是编程语言,不能使用逻辑运算。通过标签将网络上地文档格式进行统一,使分散的网络资源链接为一个整体。
- 超文本:一种组织信息地方式,通过超级链接将多种文件连接起来,包括文字、图片等。
- 标记:标签,使用<>包裹具有一定含义的内容
- 语言:非编程语言,是标记语言。
3.2 html的功能
- 展示在线文档
- 通过超链接检索
- 远程获取表单
3.3 动态网页与静态
- 静态网页:页面的内容和显示效果基本上不会发生变化,除非修改原始代码。
- 动态网页:代码不变的时候,网页的内容可以随着时间,数据或者操作环境而变化
3.4 浏览器内核
- Trident内核:代表产品ie,是微软开发的一种排版引擎,使用它的浏览器:ie,遨游,世界之窗,腾讯tt
- Gecko内核:代表产品firefox,是开源的,由c++编写的排版引擎,但是启动速度比较慢
- Webkit内核:代表产品时Safari,Chrome
- Presto内核:Opera Software开发的浏览器排版引擎,时速度最快的。
- Blink内核:由Google和Opera开发的引擎。
国内的浏览器大多数时双核驱动(Trident+Webkit / Trident+Blink)
移动端:iphone,ipad使用webkit,android 4.4以下采用webkit,以上使用blink
3.5 Html文件基本结构
头部 + 主体
<!DOCTYPE html> 申明:下面的文档使用html5的规范进行解析
<html>
<head>
<meta charset="utf-8"> <!--mate:元,主要用于完成对应设置-->
<meta name="keywords" content="">
<mate name="description" content="">
<title></title>
<link rel="stylesheet" href="外部样式">
<style>放置样式</style>
</head>
<body>
...
<script>脚本代码</script>
</body>
</html>
3.6 基本标签
- div:没有具体含义,用于布局,是块级元素。表示层
- hx:标题,x:1-6,表示不同大小的字体
- p:段落
- br:换行
- hr:分割线
- a:超文本链接,实现链接跳转 herf target title
- img:申明图像的插入 src alt title
- span:作用与div类似是用于布局的,但是span是行内元素
- ol/ul:列表 分别是有序与无序列表。内部是li标签表示列表元素
3.7 文本格式化标签(使用标签美化文本外观)
- b/strong:加粗/加粗+强调。强调主要用于搜索引擎的时候进行提取关键字
- i/em:文字倾斜/倾斜+强调。i一般可以用于添加图标,此时不会有倾斜效果
- pre:预格式化文本,保留换行和空格及宽度。一般很少使用。
- small/big(big已经在h5淘汰):缩小文本一号/放大文字一号
- sub/sup:下标/上标
3.8 块级和行内(内联)
-
块级元素:独占一行,宽高可控,没有设置宽度时默认铺满。可以包含块级和行内元素(但是p,hx,dt标签里面不可以再包含块级元素)
display:block/table/list-item
div p ul ol pre table adress… … -
行内元素:不会独占一行,会与相邻行内一行,直到该行满就自动转换。宽高不可控(设置width和height无效,除非转为块级),只能包含行内元素
display:inline/inline-block/inline-table/table-cell
span a i em strong b sub sup img td… …两个元素可以通过display进行转换。
img时行级块标签,相当于display:inline-block
3.9 W3C规范
该标准由结构(html)、表现(css) 和 行为(js) 组成
3.10 iframe框架标签
用来将多个网页文件组合成一个文件,常用的属性:name src scrolling width height frameborder marginheight marginwidth
可以使用iframe实现tab选项卡的演示
但是实际开发中不要使用iframe,因为它破坏前进后退的功能且不利于seo抓取关键字。
3.11 css介绍
-
介绍:层叠样式表,或者串样式表,由w3c定义和维护的标准,一种用于为结构化文档添加样式的计算机语言
-
使用:让结构和表现分离。css只负责表现
-
基本语法:选择器 { 属性 : 属性值 }
-
引用方式:
- 行内样式:直接在标签上书写style=“width:20px; color:red ”
- 内部样式表 内的
- 引入css文件 link标签引入.css
- 导入 在 style标签中使用@import “.css”
link和@import的区别:link可以加载多种资源,且是在页面载入的时候加载的,由于时xhtml标签因此没有兼容问题,支持js控制区更改样式。@import只可以加载css,要等网页加载完毕之后才会加载,对于低版本浏览器不支持,也不支持js控制
优先级:内联 > 内部 > 外部
3.12 css选择器
1.选择器分类
- *:匹配所有标签元素,性能很差
- 标签选择器:匹配标签名
- 类选择器:匹配class
- id选择器:匹配id(唯一)
- 派出选择器:根据上下文来确定匹配的标签 ul.list2 li 表示选择class名为list2这个列表下的所有li
- 伪类选择器:伪类表示元素的一种特殊状态,hover visited link active focus 等 还有first-child last-child这种
- 伪元素选择器:伪元素是用于创建一些文档中不存在的元素,:before :after ::selection等
- 属性选择器:匹配包含指定属性名(或者属性值也对应)的元素
- 关系选择器:
- 空格:后代选择器
- +:兄弟选择器
- > :儿子选择器
* 2.css权重*
!important 10000> 内联 1000> id 100> 类、伪类选择器 10> 标签,伪元素 1 > 通用选择器* 子选择> 相邻选择 + 同胞选择~ 0.1
3.选择器
- 选择器分组:多个选择器具有相同样式:p,h1,.box { }
- 选择器继承:子元素继承父元素的样式
3.13 某些css
- font-weight:200=lighter 400=normal 700=bold 900=bolder
- table的边框重叠消除:td样式border-collapse:collapse
3.14 css浮动布局
- 浮动就是让块级元素不独占一行,把块级元素可以脱离文档流,排在一行上
- 原理:让元素脱离文档流。
- 属性值:float : left center right none
3.15 清除浮动
- 需要到下一行的元素加上clear/或者加上空标签加上clear
- 需要到下一行的元素不与浮动元素为兄弟元素,浮动元素的父级加上overflow:hidden
- 与2一样,父元素加上after为元素,为元素上加上content:’’; dispaly:block; clear:both
3.16 css盒子模型
每个元素都是一个盒子, 标准盒模型:一个块的总宽度=width+margin(左右)+padding(左右)+border(左右)
height = line-height + vertical-align
- IE模型:border-box => 宽度=border+padding+content
- w3c模型:content-box => 宽度=content
3.17 列表样式
列表:ul ol dl(dt --> dd)
list-style: list-style-image list-style-position(inside/outside) list-style-type
3.18 css定位position
定位是设定元素在文档的位置,会将元素转换为块级
-
static静态定位,默认值,没有定位,不能设置偏移值,占用标准文档流
-
fixed固定定位,脱离文档流,相对浏览器窗口左上角做偏移,与父级没有关系,一般用于做固定导航等
-
relative相对定位,占用标准文档流,可以设置偏移值修改位置,偏移的相对原点是该元素原来位置的左上角处(并不是屏幕的左上角)
-
absolute绝对定位,脱离文档流,相对body做偏移
当绝对定位与相对定位结合使用,它相对的是relative父级元素做偏移
3.19 z-indx
z-index在static和relative上无效,可以为负值,值越大层级越上。默认值为0
网页元素的层叠规则
3.20 经典布局
-
双飞翼布局:由三列组成,两端固定,中间自适应
<!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> .container{ width: 100%; overflow: hidden; } .clo{ height: 200px; float: left; } .left{ width: 300px; background-color: blue; margin-left: -100%; } .center{ width: 100%; background-color: green; } .content{ margin: 0 200px; } .right{ width: 300px; background-color: red; margin-left: -300px; } </style> </head> <body> <div class="container"> <div class="clo center"><div class="content">center-content</div></div> <div class="clo left">left</div> <div class="clo right">right</div> </div> </body> </html>
-
圣杯布局:一样两边固定,中间自适应,但是与上面不同的是增加了相对定位和偏移设置
<style> *{ margin:0; padding: 0; } div#header, div#footer{ height: 200px; width: 100%; background-color: #eee; } .container{ padding: 0px 200px; overflow: hidden; } .col{ float: left; height: 200px; position: relative; } .left{ width: 200px; background-color: blue; margin-left: -100%; left: -200px; } .right{ width: 200px; background-color: green; margin-left: -200px; right: -200px; } .center{ width: 100%; background-color: red; } </style> </head> <body> <div id="header"></div> <div class="container"> <div class="col center">c</div> <div class="col left">l</div> <div class="col right">r</div> </div> <div id="footer"></div> </body>
-
侧边栏固定布局
- 两栏布局
- 左侧固定,右侧自适应:左侧加上margin-right为负值和position:relative,将右侧的元素调整到同行上
- 右侧固定,左侧自适应:将右侧调整到同一行
- 左右都固定: 一个左浮动,一个右浮动
- 三栏布局
- 左右固定,中自适应
- 左中固定,右侧自适应
- 左自适应,中右固定
- 两栏布局
3.21 BFC/IFC
FC:formatting context ,格式化上下文,是css2.1规范中的一个概念,是页面中的一块渲染区域,决定了子元素的定位,以及和其他元素之间的相互作用。分为bfc和ifc
-
BFC:block …块级格式化上下文
-
形成条件:浮动元素(float除none的值),定位元素(position:absolute/fixed),display:inline-block/table-cell/table-caption,overflow:hidden/auto/scroll
-
特性:
- 内部的盒子会在垂直方向,一个一个放置
- 盒子垂直方向的距离有margin决定,属于同一个bfc的两个相邻box的上下margin会重叠,值为max(margin),如果不想重叠就要将元素变为独立的盒子(bfc)
- 每个元素的左边和包含的盒子的左边相邻接,即使浮动的时候也是如此
- bfc的区域不会与float重叠,因为float元素也是bfc
- bfc就是页面上一个隔离的独立容器,容器里面的子元素不会影响到外面元素
- 计算bfc的高度时,浮动元素也参与计算
-
作用
- 解决margin重叠的问题,添加独立的bfc
- 解决浮动高度塌陷问题(父级添加overfolw:hidden)
- 解决侵占浮动元素问题,直接加overflow:hidden
-
-
IFC:inline …格式化上下文
-
形成条件:font-size, line-height, height, vertical-align
-
特性:
- ifc的元素会在一行中从左至右排列
- 在一行上的所有元素会在该区域形成一个行框
- 行宽的高度为包含框的高度,高度为行框中最高元素的高度
- 浮动的元素不会在行框中,并且浮动元素会压缩行框的宽度
- 行框的宽度容不下子元素时,子元素会换行显示,并且会产生新的行框
- 行框内的元素遵循text-align和vertical-align
注意:line-height是以该行的基线为准
-
3.22 居中布局
-
水平居中
- 针对行内元素:text-align:center
- 针对块级元素:width:auto; margin:0 auto
- 针对多个块级元素:对父元素设置 text-alian:center,对子元素设置 display:inline-block/或者使用flex布局
-
垂直居中
-
对于行内元素:
单行:设置上下padding相等,或者设置line-height和height相等
多行:设置上下padding相等,或者设置display:table-cell 和 vertical-align:middle; 或者设置flex布局;或者使用为元素
-
对于块级元素:
已知高度:子元素使用绝对布局top:50%;在使用transform:translate(-50%) / 或者margin-top:负的自身高度的一半
未知高度:子元素使用绝对布局position:absolute;top:50%;transform: translateY(-50%); 或者flex布局 justify-content: center;
-
-
水平垂直居中
-
定高定宽:
方案一:设置父元素为相对定位,给子元素设置绝对定位,top: 0; right: 0; bottom: 0; left: 0; margin: auto;
方案二:设置父元素为相对定位,给子元素设置绝对定位,left: 50%; top: 50%; margin-left: --元素宽度的一半px; margin-top: --元素高度的一半px;
-
高度和宽度未知:
先用绝对布局 top: 50%; left: 50%;,再设置 transform: translate(-50%, -50%);
使用 Flexbox:justify-content: center; align-items: center
-
3.23 比较 opacity: 0、visibility: hidden、display: none
- 结构: display:none: 会让元素完全从渲染树中消失,渲染的时候不占据任何空间, 不能点击, visibility: hidden:不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,不能点击 .opacity: 0: 不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,可以点击
- 继承:isplay: none和opacity: 0:是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示。 visibility: hidden:是继承属性,子孙节点消失由于继承了hidden,通过设置visibility: visible;可以让子孙节点显式。
- 性能:display:none : 修改元素会造成文档回流,读屏器不会读取display: none元素内容,性能消耗较大 visibility:hidden: 修改元素只会造成本元素的重绘,性能消耗较少,读屏器读取visibility: hidden元素内容. opacity: 0 : 修改元素会造成重绘,性能消耗较少
- 联系:都是让元素不可见
4.HTML5
前端html语义化: 根据内容的结构(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码,同时让浏览器的爬虫和机器很好地解析。
好处:用户体验友好,且利于seo,方便开发和维护。
4.1 html5的新特性
- 增加audio和video音视频播放,抛弃了flash
- 增加canvas画布
- 地理定位
- 增加离线缓存
- 硬件加速
- web socket ([1.16 前端实现即时通信](#1.16 前端实现即时通信))
- 增加本地存储
- 新增一些语义化标签 header section footer aside article hx em strong … …
4.2 html5网页结构–网页布局标签
- header:页首
- nav:导航,一般使用ul-li完成
- main:主体
- section:区块
- article:文章
- aside:侧边栏
- footer:页尾
4.3 语义化标签
- mark :定义高亮显示元素 高亮显示的文字
- details summary : 描述文字和摘要 摘要
- meter : 定义度量衡 属性有max min low hign value
- progress : 进度条 value min max …
- dialog : 定义对话框和窗口,open属性显示对话框
- figure : 对元素进行组合,一般用来组合一张图的标题,图片和描述
4.4 HTML5多媒体
- audio : 播放音乐或者音频 src autoplay自动播放 loop循环 controls控制条 muted静音 preload预加载,设置autoplay的时候失效
- video : 加载视频,属性和上面audio一样,还要width height poster海报路径
- embed : 嵌入内容或加载插件。src width height type 。。。 。。。
- canvas : 画布。是一个容器元素。他必须结合js使用
4.5 HTML5新增常用属性
- contentEditable : 指定元素是否可编辑。几乎可以为任何元素指定,值为true/flase
- hidden : 指定元素是否隐藏 hidden = ‘hidden’
- data-* : 用于存储页面或者应用程序的私有自定义数据
- 表单中新增属性:
- required : 规定表单元素提交时必须有输入值
- pattern : 属性规定用于验证输入字段的模式,一般结合js写
- mutiple : 多选
4.6 HTML5新表单操作
- input type = ‘color’ 颜色选择
- input type = ‘email’ 邮箱
- input type = ‘number’ 数字
- input type = ‘tel’ 电话号码
- input type = ‘url’ 链接
- input type = ‘search’ 搜索框
- input type = ‘range’ 范围
- input type = ‘data’ 日期
- input type = ‘datatime’ 时间+日期
- input type = ‘datetime-local’ : 本地日期时间
- input type = ‘year/month/week/time’ 年份/月份/时间
input的属性:autocomplete autofocus step mutiple pattern plceholder required
4.7 HTML5表单新属性
-
formaction : 修改action数据提交
-
formenctype:修改表单请求的类型
-
formmethod:修改数据提交的方法
-
form:设置表单元素属于哪个表单
-
novalidate: 不验证
5.CSS3
css3是css2.1的升级版,不同的浏览器使用的时候会有兼容性的问题,需要做兼容处理
5.1 CSS3新特性
-
[选择器](#5.3 css选择器)
-
阴影
-
形状转换(2d – > 3d) transform
-
变形
-
过渡动画,帧动画 transition animation
-
边框 border/border-radiaus/box-shadow/border-image
-
背景
-
多重背景:background:背景色 图片 平铺方式 位置 ,背景色 图片 平铺方式 位置,… …eg:background:url(),url(),url()可以将多张图拼在一起
-
background-size background-clip background-origin
-
渐变背景 background-image
线性渐变 line-gradient(方向,颜色1 百分比,颜色2 百分比, … … )
径向渐变 radial-gradient(形状 渐变大小 at 位置,颜色1, 颜色2 , … …)
-
-
反射 -webkit-box-reflect
-
[文本](#5.4 文本)
-
颜色(rgba/hsl/hsla)
-
颜色(rgba/hsl/hsla)
-
滤镜(filter)
-
弹性布局 flex
-
栅格布局 grid
-
多列布局
-
盒模型 允许使用某种方式定义某些元素,以适应指定的区域。box-sizing: content-box/ border-box
-
web字体
-
媒体查询 就在监听屏幕尺寸的变化,在不同尺寸的时候显示不同的样式
5.2 兼容处理
-
[主流浏览器内核](#3.4 浏览器内核)
-
添加厂商前缀
IE:-ms- Chrome&Safari: -webkit- Firefox: -moz- Opera: -o-
5.3 css选择器
-
属性选择器 p[class=content]
-
结构性伪类 :root body first-child … …
-
目标伪类 :target
-
ui元素状态伪类 :enabled :checked ::selection(用户选中的时候) :disabled
-
否定伪类 :not()
-
通用兄弟选择器 E ~ F 匹配e之后的f元素
5.4 文本
-
文本阴影text-shadow:水平偏移 垂直偏移 模糊 阴影尺寸 颜色
-
文本自动换行word-wrap:normal | break-word
-
单词拆分word-break:normal | break-all | keep-all
-
文本拆分text-break:
-
文本溢出
-
单文本溢出text-overflow : ellipsis | clip | string
-
多文本溢出
display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:行数; pverflow:hidden;
-
-
文字渐变色
background-image:liner-gradient(); background-clip:text; text-fill-color:transparent;
5.5 动画
- 2D 或 3D 转换 动画
transform方法 详解transform (注意x,y,z轴的定义,rotateY和Z是怎么旋转的)
transform-origin更改基点,一般与旋转配合使用
perspective 让子元素获得透视效果,单位是长度;主流浏览器都不支持,谷歌加上-webkit-前缀
transform-style 在3d空间呈现被嵌套的元素,与transform一同使用,flat(默认值) | preserve-3d
-
过渡动画
transition : property duration timing-function delay; 默认值 all 0 ease 0
property :可以使用的属性有
颜色:color bgc-color border-color outline-color
位置:bgc-position left right top bottom
数字:height width line-height text-indent vertical-align outline-offset font-size margin padding border-spacing letter-spacing word-spacing opacity visibility z-index font-weight zoom
组合:text-shadow transform box-shadow clip
其他:gradient
timing-function:动画函数 linear ease ease-in(先慢后快) ease-out ease-in-out cubic-bezier
-
关键帧动画
步骤:
1.设置关键帧
@keyframes 动画名称 { 0%{样式} ===from{} 100%{样式} ===to{} } @keyframes 动画名称 { 0%{} 25%{} ... 100%{} }
2.实施动画
常规用法 animation:name(就是上面@keyframes后面的动画名称) duration timing-function delay iteration-count(循环次数num/infinite) direction(播放完毕是否反向播放normal/alternate)
animation-play-state(动画播放或者停止paused/running)
5.6 布局
-
多列布局
column-count 规定分成几列 number | auto
cllumn-width 设置列的宽度 length | auto
column : width | count
简写模式column-gap 设置栏间距 number | auto
column-rule 列之间的分隔线设置,width | style | color 与border的设置很像,可以分开指定
-
box布局 (弹性布局)
弹性布局是当页面需要适应不同屏幕大小和设备时使用
display:box;
box-orient: horizontal | vertical | inherit; 该属性定义父元素的子元素是如何排列的。
box-pack: start | end | center | justify; 该属性定义父元素的子元素是如何排列的。但是注意这种排列是沿box-orient方向的
box-align: baseline | center | end | start | stretch
box-flex: 0 | 任意数字; 该属性让子容器针对父容器的宽度按一定规则进行划分
-
flex布局 (弹性布局)
display: flex ; 需要处理浏览器兼容问题
flex-direction 指定了弹性子元素在父容器上的位置,排列的规则。row(横向排) row-reserve column column-reverse
justify-content 把弹性元素沿着弹性容器主轴线对齐 。flex-start(紧凑左对齐) flex-end(紧凑右对齐) center(紧凑居中对齐) space-between(首尾贴边,其余等分) space-around(等分)
align-items 子元素在纵轴上的对齐方式 flex-start(顶端对齐) flex-end(底端对齐) center(居中对齐) baseline(以文字的基线对齐) stretch(纵向拉伸对齐,适用于没有指定高度时)
flex-grow 应用于子元素上,表示指定元素的放大比例。number 适用于没有指定宽度的时候,对屏幕进行划分。
flex 用于指定子元素空间分配 auto(=1 1 auto) initial(=0 1 auto) none(=0 0 auto) inherit
flex == flex-grow(放大比例) flex-shrink(收缩比例) flex-basis(基本宽度)
-
响应式布局
responsive design,在不同分辨率屏幕上的展示方式,通过响应式设计,使得网页在不同设备上的阅读体验好。
响应式和自适应区别:(面试点)
响应式只开发一套代码,针对不同的设备对代码进行处理,展现不同的布局和内容。但是自适应是开发多套代码界面,通过检测窗口的分辨率判断设备,然后请求返回不同的页面。
响应式布局等同于流动网格布局,但是自适应是使用固定分割点进行布局
自适应布局给出了更多的设计空间,只用考虑几种不同的状态就行。但是响应式需要考虑上百种不同的状态,更加复杂。
- 响应式布局开发的实现方式:媒体查询 百分比布局 rem布局 视口单位布局
- 设计步骤:1,设置meta
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=n,minimum-scale=1.0, maximum-scale=1.0">这个内容只能被移动端识别
2,通过媒体查询设置样式 3,设置多种视图的宽度(此时宽度不可以再写死,一般是百分比或者vw/vh/rem),图片的缩放问题,其他属性的处理
5.7 媒体查询
步骤:
-
设置meta标签
-
设置IE的渲染方式
-
引入兼容的js
-
进css3提供的媒体查询
-
引入外部不同的css文件
-
style里面使用@media
-
5.8 web字体
开发的时候使用@font-face引入外部字体
@font-face {
font-family: xxx;
src:url(文件路径) format(字体文件格式处理兼容), url(文件路径) format(字体文件格式处理兼容);/*同时引入多个文件可以处理兼容*/
}
p{
font-family:xxx;
}
5.9 iconfont
阿里提供的图标:在官网将需要的图标加入购物车之后,下载,下载的就是一些iconfont的字体文件和css文件,css引入项目中,然后使用class=“iconfont iconname"的方式或者编码方式去使用。可以使用font-size等去修改图标基础样式
<div class="iconfont home"></div>
<div class="iconfont">̳</div>
6.JS
6.1 异步加载脚本
默认情况下,****js是同步加载的,js加载时是阻塞的****,后面的元素要等待js加载完后才能进行加载,在一些页面就会出现白屏效果,所以需要异步加载js。
有三种实现方案,第一种是给script标签加一个defer属性,脚本会延迟到整个页面加载完后再执行,按照原本的顺序执行,同时会在document的DOMContentLoaded之前执行。
第二种是给script标签加一个async属性,脚本会立刻被异步加载,async不能保证脚本的顺序性,但都会在onload之前完成。
第三种是创建script标签,插入到dom中,加载完后回调。
6.2 作用域和作用域链
-
作用域:是变量和函数的可访问范围,作用域控制着变量和函数的可见性和生命周期,js中作用域主要分为全局作用域和局部作用域。在浏览器中,全局作用域就是window对象,声明一个函数,会在函数内部创建一个局部作用域。
注意:表面上看,在js中块级作用域(块级作用域指的是被{}包起来的部分)是不存在的,比如说if{…} for(){…},但是使用with,try/catch,let,const可以创建块级作用域。
-
作用域链:声明一个函数时,局部作用域一级一级向上包起来,就形成了作用域链。作用域链保证了对执行环境有访问权限的变量和对象的有序访问。内部环境可以通过作用域链访问外部环境,而外部环境不能通过作用域链访问内部坏境中的变量和对象。作用域的前端是当前执行代码所在环境的变量对象,终端是全局作用域。
6.3 垃圾回收
垃圾回收是找到不再继续使用的变量,然后释放他们的内存。Js的垃圾回收是自动的。
方案一:通过标记-清除算法来进行垃圾回收的,过程是垃圾回收器判断内存中的对象是否可达,将具有可达性的对象进行标记,除了标记的对象外,删除未被标记的对象。
方案二:引用计数,跟踪每个值被引用的次数,当次数为0时就可以回收了。问题是循环引用(解除变量引用助于消除循环引用,也有利于垃圾回收)。
6.4 原型与原型链
实例Person1 原型Person prototype
通过使用 hasOwnProperty()方法,用于判断实例属性是否存在的。(对原型属性判断不了,判断原型属性使用hasPrototypeProperty,该方法只对唯一存在原型中的属性返回true,若属性同时也存在于实例中,返回false)。然后 属性名 in 实例 中的 in 操作符对原型属性和实例属性均能判断。配合hasOwnPrototype一起使用,可以判断属性到底是位于什么上的。
function hasPrototypeProperty(object, name){
return !object.hasOwnProperty(name) && (name in object);
}
函数/类实例/对象,都会具有一个prototype属性,指向函数/类/对象的原型对象。这个原型对象具有constructor属性,指向prototype所在地函数/类/对象。所有引用类型(函数,数组,对象)都拥有_proto_
属性(隐式原型),通过_proto_
连接对象和原型组成了原型链。
使用原型对象的好处是可以让所有对象实例共享所包含的属性和方法。
6.5 继承
ECMAScript 只支持实现继承,而且其实现继承主要是依靠原型链来实现的。
-
原型链:将父类实例赋给子类原型,无法传参.(原型对象等于另一个类型的实例)
-
构造函数:在子类构造函数内部调用父类,无法复用父类中的方法
-
组合模式:原型链+构造函数,原型链继承原型属性和方法,构造函数继承实例属性。缺点:父类调用两次:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); //第二次调用 SuperType() this.age = age; } SubType.prototype = new SuperType(); //第一次调用 SuperType() SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); };
-
原型式:基于已有对象创建新对象,并创建自定义类型
function obj(o){ //o是已经存在的对象 function F(){} F.prototype = o; return new F(); }
-
寄生式:原型式+工厂模式,封装创建:即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象
function create(o){ var f= obj(o); f.run = function () { return this.arr;//同样,会共享引用 }; return f;o }//新对象不仅具有 o的所有属性和方法,而且还有自己的 run()方法。
-
寄生组合式:通过借用构造函数来继承属性,通过原型链继承方法
function inheritPrototype(subType, superType){ var protoType = Object.create(superType.prototype);//创建对象,copy而不是调用,这里就与组合模式相比,减少一次对父类的调用 protoType.constructor = subType;//增强对象 subType.prototype = protoType;//指定对象 } //examples function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); //仅一次调用supertype this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); };
6.6 闭包
闭包:是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式是,在一个函数内部创建另外一个函数。
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生
了闭包。 ———<你不知道的javascript>
function foo() {
let a = 2;
function bar() {
console.log(a++);//这就是闭包。按道理说,bar是在foo作用域中的,只有foo可以使用它;
}
return bar();//返回出去是很重要的
}
var f = foo();//实际上 f是调用的bar()
f();//2 f()也就是bar()竟然在自己定义的词法作用域以外的地方执行,这就是闭包的作用
f();//3
//foo()在执行之后,按理说会被垃圾回收机制回收,但是bar()闭包可以将这个内部作用域锁定(bar()依然持有对该作用域的引用,而这个引用就叫作闭包),这样就还是可以打印出a的值。且当你第二次调用f()的时候,a并不是foo初始化的2,为什么?都说了f()实际上调用的是bar(),内部作用域是被bar控制的,但是bar()里面用到的a已经在第一次使用f()的时候被修改了,第二次调用a的时候a已经是3了。
for (var i=1; i<=5; i++)
{
(function(j) { //j是形参,使用到了闭包,所以每次循环会创建一个新的作用域
setTimeout( function timer() {
console.log(j);
}, j*1000);
})( i ); //i是实参 函数表达式(function(形参))(实参)
}
//上面可以简化为
for (let i=0; i<=5; i++) { //let声明,可以用来劫持块作用域
setTimeout(i)(function timer() {
console.log(i);
}, i*1000)
}
模块机制
可以使用闭包实现模块机制
function foo(){
var a = 1;
function say(){console.log(a)}
function change(){a=2}
return {
say:say,
change:change
}
}
var bar = foo() //实际上bar是{say:say,change:change}
bar.say();//a=1
bar.change();//a=2
在现在es6的发展上,模块使用的是export default/export进行导出api,import 导入,module导入整个模块
6.7 this
this是在运行时基于函数的执行环境绑定的。有四种绑定规则,****默认绑定、隐式绑定、显示绑定、new 绑定****。默认绑定一般指的是将全局对象绑定到this,隐式绑定一般是某个对象上触发的,显示绑定指的是使用call和apply,主要是改变对象的prototype关联对象。 如果函数或者方法调用之前带有关键字new,它就构成构造函数调用,对于this绑定来说,称为new绑定
6.8 内存泄漏
- 内存泄漏:内存泄漏指得是由于疏忽或错误造成程序未能释放已经不再使用的内存。
- 造成原因:
- 意外的全局变量,未声明的变量缓存了大量数据,只有在页面关闭或刷新时才能释放;
- 没有去掉console.log,因为在代码运行之后需要在开发工具能查看对象信息,所以传递给console.log的对象是不能 被垃圾回收。
- 闭包,settimeout/setinterval,控制台日志
6.9 事件
页面上的交互通过事件实现,事件流是从页面中接收到事件的顺序
- 事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到document为止。
- 事件捕获会从document开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。
- 事件委托依靠的就是事件冒泡和捕获的机制,通过监听一个父元素,来给不同的子元素绑定事件,减少监听次数,从而提升速度。
6.10 JSON
- Json是一种轻量级数据交换格式。Json可以由简单值,对象和数组构成,属性必须加上双引号。流行的原因是能把json字符串解析成js对象。常用的方法有Json.stringify()和json.parse(),json.stringify用于将对象序列化为json字符串,json.parse用于将json字符串序列化为js对象。
- json字符串,json对象(区别)
6.11 Web存储
- Cookie:在客户端保存数据的一种存储机制,一般保存的是会话信息。Cookie会与服务端交互,存在安全性和带宽浪费情况,cookie大小数量受限。所以,h5引入了Web Storage与本地数据库
- Web Storage:主要包含sessionStorage和localStorage,存储空间更大,安全性更高,操作更方便。
- 本地数据库:指的是IndexedDB使用它可以在客户端本地建立一个数据库,原本必须保存在服务器端数据库中的内容现在可以直接保存在客户端本地了,这大大减轻了服务器端的负担,同时也加快了访问数据的速度。
6.12 类型转换
-
任何js类型值都可以转成boolen
undefined,null,0,-0,NaN,””=>false 其他所有值=>true
-
对象转换成其他:原理是先调用valueOf,然后调用toString,
-
== vs ===
-
== 先转换类型,再进行比较
若一个为 null ,一个为 undefined ,则相等 若一个为字符串,一个为数字,则将字符串->数字,再比较 若一个为 true ,则转为1比较; 若一个为 false ,则转为0比较 若一个为对象,一个为字符串/数值,则将对象转为基础类型再比较 undefined 和 null 任何有意义值比较都是 false NaN === NaN false
-
===完全等于,包括类型也要完全一致
-
6.13 类型获取
-
typeof:对于基本类型,除了 null 都可以显示正确的类型,对于对象,除了函数都会显示 object
var arr = [1,2,3]; console.log(typeof arr.valueOf());//object console.log(arr.valueOf() instanceof Array);//true
-
instanceof:可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。
6.14 null和 undefined
undefined===null => false
null == undefined =>true
typeof(null) (object) == typeof(undefined) (undefined) => false
6.15 深浅拷贝
-
浅拷贝:仅是复制了引用,彼此之间的操作会相互影响数据。
-
深拷贝:重新分配内存,不同的地址,相同的值,操作互不影响。
-
Object.assign({},o1);一维对象深拷贝。二维不行
-
扩展运算符 …
-
JSON.parse(JSON.stringify(obj)) 对function undefined的对象不能深拷贝,其余均可
-
递归深拷贝
function deepCopy(obj){ var res = (obj instanceof Array)? [] : {}; for(let key in obj){ if(obj[key] && typeof obj[key]=='object'){ res[key] = deepCopy(obj[key]); }else{ res[key] = obj[key]; } } return res; }
-
6.16 原生js操作dom
-
查找结点 document.xx
通过id查找dom结点:getElementByID('') 通过class属性名:getElementByClassName() 通过标签名称:getElementByTagNames() 通过指定名称:getElementByName() 匹配选择器:只返回匹配的第一个querySelector() 匹配选择器,返回匹配的所有:querySelectorAll() 获取页面中的html标签:documentElement 获取页面中的body标签:body 获取页面中所有元素节点的对象集合型:all('')
-
新建节点
新建元素节点:createElement() 新建属性节点:createAttribute() 新建文本节点:createTextNode() 新建注释节点:createComment() 新建文档片段节点:createDocumentFrament()
-
增加节点
向父元素的最后一个子节点追加新节点:appendChild() 向父节点的某个特定子节点之前插入新节点:insertBefore() 给元素增加属性节点和设置值:setAttribute()
-
删除节点
删除已有的子节点,返回值为删除节点:parentNode.removeChild(existingChild); 删除具有指定节点的属性,无返回值:removeAttribute(‘属性名’); 删除指定属性,返回值为删除的属性:removeAttributeNode(attrNode);
-
修改节点
用新节点替换父节点中已有的子节点:parentNode.replaceChild(newChild, existingChild); 修改已有节点的属性值:setAttributeNode( attributeName); 修改已有节点的属性值:setAttribute(attributeName,attributeValue)
6.17 JS闭环??
6.18 arguments转换数组
arguments实质上是 函数内一个內建对象,它包含函数接收到的所有变量,有索引和length属性等,但是并不能使用数组方法。
转换为数组
-
可以使用额外的数组空间,对arguments进行for循环,讲变量取出来放在arr里面
-
使用arr=[].slice.call(arguments) 通过call使其能调用数组中的slice方法,从而使其能转为数组
-
[…arguments]
最好使用循环转化为数组,因为slice可能会不利于优化
6.19 提升
函数知识点:区分函数的两种写法
-
函数声明:function作为开头是函数声明
function xx () { ... }
-
函数表达式:开头不是function的是函数表达式
(function xx(){ ... })() //第一对括号里面的是函数表达式,第二对括号是将前面的函数表达式立即执行 var xx = function yy(){ ... }
提升:所有的声明都会被移动到各自作用域的顶端。
现有声明,后有赋值;函数声明和变量声明都会被提升。
a = 2; //赋值声明,保留在原地
var a; //定义声明,会被提升
console.log(a) //2
/*---------*/
console.log(a) //undefined
var a = 2; //var a=2; ==》 var a; a=2; 其中var a定义声明会被提升,但是a=2赋值声明会停在原地。
/*---------*/
foo()
function foo(){ ... } //函数声明也会被提升,上面的foo()调用没有问题
/*---------*/
foo() //TypeError
var foo = function bar(){ ... } //函数表达式==》var foo这个会被提升; foo = function bar()停在原地,上面的foo()会报错
7.Ajax
- ajax: asynchronous Javascript and XML(异步的js和xml),是一种运用于浏览器的技术,可以在浏览器和服务器之间使用异步通信机制进行数据通信,从而允许浏览器向服务器获取信息。
- 优点:可以不重新加载整个页面就可以与服务器进行数据交换并更新部分页面内容
- 缺点:不支持浏览器回退按钮,不容易调试,有安全问题:会暴露交互的细节
- 原理:ajax的工作原理相当于在用户和服务器之间加了一个中间层,使用户操作和服务器响应异步化。主要是XMLHttp组件中的XMLHttpRequest对象,可以实现浏览器端和服务器端的异步通信。
- 实现过程:检测浏览器支持XHR对象->创建XHR对象->使用open方法,传入请求方式,url,异步或同步->send方法发送->通过监听onreadystatechange事件,readyState为4时,200进行响应responseText。
- 状态码:
- 0 请求未初始化
- 1 服务器连接已建立
- 2 请求已接收
- 3 请求处理中
- 4 请求已完成,且响应就绪
- 与http请求的区别:
- ajax常用于获取json数据,http获取html资源
- ajax使用xmlhttprequest对象请求服务器进行通信,http使用httprequest对象
- ajax请求头多一个x-requested-with参数
- ajax和http请求都是单向的(客户端->服务器),但是websocket是双向通信
8.跨域
8.1 跨域
跨域:从一个域名去请求另外一个域名的资源,由于浏览器的同源策略(协议端口域名要相同),浏览器在当前域名下不能执行其他域名网站的脚本。
8.2 解决跨域jsonp方案
-
jsonp:本质上是hack,他利用
8.3 最流行的跨域方案cros
- cros:是目前主流的跨域解决方案,跨域资源共享cros是一种机制,属于跨源ajax请求的根本解决方法。使用自定义的http头服务器***access-control-allow-origin***来告诉浏览器让运行在一个origin上的web应用被准许访问来自不同源服务器上指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议、端口请求资源时,会发起跨域http请求。
- 缺点:兼容问题
8.4 最方便的跨域方案Nginx
Nginx时一款极其强大的web服务器,轻量级、启动快、高并发。现在的项目中大多都使用Nginx进行反向代理。
8.5 其他跨域方案
- postMessage():HTML5 XMLHttpRequest中的api,该方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文档、多窗口、跨域消息传递
- WebSocket:建立连接后,Websocket的server和client都可以主动向对方发或者接数据。连接建立好之后server和client之间的双向通信与HTTP无关,因此可以跨域。
- window.name + iframe:window.name属性值在不同的页面或者不同的域名下加载后依旧存在。
- location.hash + iframe:a.html欲与c.html跨域相互通信,通过中间页b.html来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
- document.domain + iframe:该方式只能用于二级域名相同的情况。比如 a.test.com 和 b.test.com 适用于该方式,我们只需要给页面添加 document.domain =‘test.com’ 表示二级域名都相同就可以实现跨域,两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
9.缓存
9.1 缓存介绍
缓存可以说是性能优化中简单高效的一种方式。优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且而由于缓存文件可以重复利用,可以减少带宽,降低网络负荷。
9.2 缓存分类
根据是否需要向服务器重新发起http请求将缓存过程分为强制缓存和协商缓存。
-
强制缓存:只要缓存没过有效期,就强制读取缓存,响应code为200。该类缓存必定是要持久化到disk的。Firefox中并没有对强制缓存进行进一步的分类。但谷歌浏览器的处理略有不同,分为两种:一种是(from disk cache),另一种是(from memory cache)
-
协商缓存: 每次读取缓存时,先到服务器端去验证一下是否有改变,如果有就获取新的,没有从缓存中读取,响应code为304
-
强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回304,继续使用缓存。
9.3 缓存应用场景
-
频繁变动的资源
Cache-Control: no-cache
对于频繁变化的资源,首先需要使用Cache-Control: no-cache使得浏览器每次都请求服务器,然后配合ETag或者Last-Modified来验证资源是否有效。这样不能减少请求量,但是可以减少响应的数据大小。
-
不常变化的资源
Cache-Control: max-age=31536000(一年)
对于这类资源,给Cache-Control设置很大的max-age这样浏览器之后请求相同的url会命中强制缓存。
9.4 缓存位置
-
service worker
Service Worker 是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。Service Worker的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
Service Worker 实现缓存功能一般分为三个步骤:首先需要先注册 Service Worker,然后监听到 install 事件以后就可以缓存需要的文件,那么在下次用户访问的时候就可以通过拦截请求的方式查询是否存在缓存,存在缓存的话就可以直接读取缓存文件,否则就去请求数据。
当 Service Worker 没有命中缓存的时候,我们需要去调用 fetch 函数获取数据。也就是说,如果我们没有在 Service Worker 命中缓存的话,会根据缓存查找优先级去查找数据。但是不管我们是从 Memory Cache 中还是从网络请求中获取的数据,浏览器都会显示我们是从 Service Worker 中获取的内容。
-
memory cache
Memory Cache 也就是内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。 一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。
那么既然内存缓存这么高效,我们是不是能让数据都存放在内存中呢?这是不可能的。计算机中的内存一定比硬盘容量小得多,操作系统需要精打细算内存的使用,所以能让我们使用的内存必然不多。当我们访问过页面以后,再次刷新页面,可以发现很多数据都来自于内存缓存。
内存缓存中有一块重要的缓存资源是preloader相关指令(例如)下载的资源。总所周知preloader的相关指令已经是页面优化的常见手段之一,它可以一边解析js/css文件,一边网络请求下一个资源。
需要注意的事情是,内存缓存在缓存资源时并不关心返回资源的HTTP缓存头Cache-Control是什么值,同时资源的匹配也并非仅仅是对URL做匹配,还可能会对Content-Type,CORS等其他特征做校验。
-
disk cache
Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比之 Memory Cache 胜在容量和存储时效性上。
在所有浏览器缓存中,Disk Cache 覆盖面基本是最大的。它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据。绝大部分的缓存都来自 Disk Cache
浏览器会把哪些文件丢进内存中?哪些丢进硬盘中?关于这点,网上说法不一,不过以下观点比较靠得住:
对于大文件来说,大概率是不存储在内存中的,反之优先。当前系统内存使用率高的话,文件优先存储进硬盘
-
push cache
Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在Chrome浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令。
10.性能优化
10.1 DNS解析优化
-
解析过程:DNS查询过程:浏览器缓存→系统缓存→路由器缓存→hosts文件→ISP DNS缓存→递归搜索
-
DNS缓存:只要有DNS解析的地方就有DNS缓存,默认浏览器会缓存访问过域名的ip地址,设置系统缓存。
-
DNS预解析:
1、告诉浏览器,页面要进行DNS预解析
<meta http-equiv='x-dns-prefetch- control' content='on'>
2、通过link标签指定域名进行cdn域名预解析
<link rel="dns-prefetch" href = "//www.taobao.com">
-
DNS负载均衡
10.2 减少http请求与连接时间
-
TCP连接
- TCP长连接:服务器在完成http请求之后不断开TCP连接而是挂起,后续有请求可以直接在这个TCP上发送。但是缺点是保持长连接会消耗服务端资源。
- 采用HTTP/2:HTTP/2多路复用的特点是允许多个HTTP请求在同一个TCP连接上发送,可以节省多次建立TCP连接的时间。
-
HTTP请求优化:减少请求次数,减少单次请求花费的时间
-
减少请求次数:
- 静态资源合并:对于JS和CSS文件可以在构建阶段通过构建工具将它们打包成一到两个文件。
- 雪碧图:将多个图片合成一张图,但是如果有一个图要修改就要更改整个图,不利于缓存
- base64化:增大文件的体积,增大css的体积,阻碍页面的渲染。
-
减少单次请求花费时间
主要是减少请求的文件的体积,自然可以减少时间。
- 压缩文件:
- 构建阶段压缩:通过删除多余空格和空行以及变量名替换(用字符较少的变量名替换字符较多的变量名)减少文件的字符数量。
- HTTP 压缩(内容编码):对 HTTP 所传的内容重新编码,缩小文件的体积,例如 Gzip 压缩。
- 拆分资源:将文件按 url 路径(或者采用更小粒度)进行拆分,优先加载关键渲染路径所依赖的文件,其他文件在需要的时候再异步请求
- 压缩文件:
-
缓存
减少网络IO消耗,提高页面的访问速度
- HTTP缓存:[分为强缓存和协商缓存](#8.2 缓存分类)
- [Service Worker](#8.4 缓存位置):可以实现离线缓存
- IndexDB缓存:H5离线应用
- manifest应用缓存:断网依旧可以访问域名 链接。(已应用网站:https://www.zybuluo.com)
-
10.3 浏览器渲染优化
浏览器渲染流程:JS执行 => CSS 样式渲染 => 布局 => 绘制 => 合成
对上面的流程有些不解,与一般的过程似乎有区别,DOM+CSSOM生成渲染树 https://www.jianshu.com/p/e6252dc9be32
-
js执行优化
1)对于动画效果的实现,避免使用 setTimeout 或 setInterval,使用 requestAnimationFrame
2)如果不需要访问 DOM,可以将长时间运行的 Javascript 工作从主线程移动 worker 线程
3)如果必须在主线程上执行大型任务,可以将大型任务分割为多个微任务,每个微任务所占时间不超过几毫秒
-
css样式渲染优化:降低选择器的复杂性, 尽量将嵌套层减少到最小 。
-
布局优化
布局是浏览器计算各元素的几何信息的过程,包括元素的大小和在页面中的位置。
1)尽可能避免布局操作
几何属性(高度、宽度、位置等)的更改都会引发布局计算,而布局几乎总是作用到整个文档,所以会耗费大量性能。
2)使用 flexbox 布局模型
flexbox 布局模型的性能更好。
-
绘制优化:绘制是浏览器填充像素的过程。绘制通常是渲染过程中性能开销最大的部分,应该尽可能避免绘制。
-
合成优化(composite):合成是将页面已绘制的部分放在一起在屏幕上显示的过程。页面中的合成层数量不宜太多(需要管理的合成层数量过多影响性能),如果没有必要,还是不要将元素提升为合成层。
坚持使用 transform 和 opacity 属性更改来实现动画
使用 transform 和 opacity 时要注意的是,这些属性所在的元素应处于其自身的合成器层(will-change 提升)。
10.4 雪碧图
雪碧图:也叫精灵图,是把多张小图放在一张大图上,目的是为了减少请求次数,达到优化目的。
- 优点:减少http请求次数;减少图片数量,提升网页加载速度;减少网络宽带占用;
- 缺点:提高了王爷开发和维护成本;合并内容性图片会影响页面可读性,语义化降低。
- 应用场景:一般只有描述性图片用来制作雪碧图,比如页面中使用的各种小图标,按钮背景图,及各种效果的图片,适合做成雪碧图;对于img标签设置的内容性图片,是不能合成到雪碧图的;开发游戏使用的素材图片。
11.事件循环
JS的解析是由浏览器中的JS解析引擎完成的。JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始。但是又存在某些任务比较耗时,如IO读写等,所以需要一种机制可以先执行排在后面的任务,这就是:同步任务(synchronous)和异步任务(asynchronous)。JS的执行机制就可以看做是一个主线程加上一个任务队列(task queue)。同步任务就是放在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务,这个过程是不断重复的,所以又叫做事件循环(Event loop)。
(1)什么是进程?
进程是CPU进行资源分配的基本单位
(2)什么是线程?
线程是CPU调度的最小单位,是建立在进程的基础上运行的单位,共享进程的内存空间。
那么我们可以得出结论:
1、进程是会占用系统资源;2、一个进程内可以存在一个或者多个线程,这就是单线程和多线程;3、无论是单线程还是多线程都是在一个进程内。
11.1 浏览器
关于微任务和宏任务在浏览器的执行顺序是这样的:执行一只task(宏任务),执行完micro-task队列 (微任务)。如此循环往复下去。
常见的 task(宏任务)比如:setTimeout、setInterval、script(整体代码)、 I/O 操作、UI 渲染等。
常见的 micro-task 比如: new Promise().then(回调)、MutationObserver(html5新特性) 等。
11.2 Node
未完待续
12.ES6
12.1 let const
增加块级作用域,在块级作用域中可以使用
不允许在同作用域中重复声明同一个变量
- let 声明的变量只在 let 命令所在的代码块内有
- const 只读的常量,定义的时候必须初始化
12.2 解构赋值
快速获取数组或对象中的元素或属性,而无需使用对索引或属性一个一个赋值了
let [a, b, c] = [1, 2, 3];
let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; // foo = 'aaa' // bar = 'bbb'
12.3 扩展运算符
扩展运算符(spread)是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
console.log(...[1,2,3]) //1 2 3
12.4 rest运算符
ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
function add(...values) {
//不使用rest运算符的话,values=1,且执行下面的代码会报错,以为一个数并不是可以迭代的iterator对象
//使用之后,values= [1,2,3]
let sum = 0;
for(let val of values) {
sum += val;
}
return sum;
}
console.log(add(1,2,3)) //6
12.5 symbol
ES6的基本数据类型:Number String Boolen Object Null Undefined 还加上了Symbol
Symbol:表示独一无二的值,最大的用处是定义对象的唯一属性名
let sy = Symbol("KK");//Symbol()写法没有登记机制
console.log(sy); // Symbol(KK)
typeof(sy); // "symbol"
// 相同参数 Symbol() 返回的值不相等
let sy1 = Symbol("kk");
sy === sy1; // false
如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
let sy = Symbol('kk');
let sy1 = Symbol('yy')
let my = {[sy]:'key1',[sy1]:'key2'}
console.log(my);//{ [Symbol(kk)]: 'key1', [Symbol(yy)]: 'key2' }
Object.getOwnPropertySymbols(my);//[ Symbol(kk), Symbol(yy) ]
Reflect.ownKeys(my);//[ Symbol(kk), Symbol(yy) ]
Symbol.for() 类似单例模式,首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值(相当于浅拷贝),若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。 调用Symbol.for("cat")
30 次,每次都会返回同一个 Symbol 值,但是调用Symbol("cat")
30 次,会返回 30 个不同的 Symbol 值。
Symbol()写法没有登记机制 ,Symbol.for()有登记机制。
let y1 = Symbol('yellow');
let y2 = Symbol.for('yellow');//Symbol.for()创建的值会被登记在全局环境中供搜索,而Symbol()创建的值不会被登记,所以Symbol.for("yellow")依然会新创建一个Symbol值,而不是返回Symbol("yellow")创建的值。
let y3 = Symbol.for('yellow');//这是全局环境中也已经存在这个Symbol值,所以直接返回y1
console.log(y1 == y2) //false 创建的环境不同
console.log(y3 == y2) //true
Symbol.keyFor()方法返回一个已经登记的Symbol的key
let b1 = Symbol.for('blue');//全局中已登记
console.log(Symbol.keyFor(b2)) //"blue"
let b2 = Symbol('blue2');//未登记
console.log(Symbol.keyFor(b2)) //undefined
12.6 箭头函数 =>
- 函数体内的this对象,是定义是所在的对象(定义时代码外层块的this指向),不是使用时候的对象,因为箭头函数内部没有自己的this
- 不可以仿作构造函数,不可以使用new命令
- 不可以使用arguments对象,在函数体内不存在。但是可以使用rest参数
- 不可以使用yeild,不能用作生成器Generator函数
12.7 Set/WeakSet
-
Set:允许存储任何类型值,不重复的值的集合。
- add(value):添加某个值,返回Set结构本身。
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
- has(value):返回一个布尔值,表示该值是否为Set成员。
- clear():清除所有成员,没有返回值。
-
WeakSet:与Set一样,不重复的值的集合;WeakSet 的成员只能是对象,而不能是其他类型的值,弱引用(垃圾回收机制会自动回收该对象所占用的内存,不考虑WeakSet的引用 ), 只有
add
、delete
、has
三个方法
12.8 Map/WeakMap
-
Map:一种更完善的 Hash 结构实现,键值对的集合。
- size属性 map.size获取map大小
- set(key,value):设置新的键值对
- get(key):获取指定键的值
- has(key):是否有该键名
- delete(key):删除指定键值对
- clear(): 整个map清空
遍历方法:
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回键值对的遍历器
- forEach():使用回调函数遍历每个成员
-
WeakMap: 是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。 拥有
get
、has
、delete
方法。
12.9 for…of…
一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for…of循环遍历它的成员。也就是说,for…of循环内部调用的是数据结构的Symbol.iterator方法。
for…of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。
12.10 Promise
-
Promise被设计用于改善JS中的异步编程,与事件及回调函数相比,在异步操作方面提供了更多的控制权与组合性。可以避免层层嵌套的回调函数(回调地狱)。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
-
状态:挂起(pending)、已完成(resolve)、已拒绝(reject)
-
缺陷:无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
-
具体:
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去在.then()中接受;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去在.then()中接受。
var p = new Promise(function(resolve, reject) {
//异步任务代码
})
p.then(function(res){
//成功的结果
console.log(res)
},function(err){
//失败的结果
console.log(err)
})
.then(...)
.then(...)//层层回调,使用链式,不再是嵌套形成回调地狱
-
Promise.all() 将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
Promise.all([p1,p2,p3]).then((res) => { console.log(res);//成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的 }).catch((err) => { console.log(err); })
-
Promise.race() 将多个Promise实例包装成一个, 哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
Promise.race([p1,p2,p3]).then((res) => { console.log(res); }).catch((err) => { console.log(err); })
12.11 Generator函数
-
与普通函数区别
-
一是在 function 后面,函数名之前有个 *
-
函数内部有 yield 表达式。
-
next()
方法可以带一个参数,该参数就会被当作上一个yield
表达式的返回值。function* func() { console.log('1'); var x = yield '1';//第一个next()执行到这里停止,有参数可接受,x='hh' console.log('2'+x); yield '2';//第二个next执行到这里, console.log('3'); return '3'; } var f = func(); f.next();//1 {value:'1',done:false} f.next('hh');//2 {value:'2',done:false} f.next();//3hh {value:'3',done:true} f.next();//{value:undefined;done:true}
-
-
应用场景
- 异步操作:将异步操作写在yield里面,需要的时候就调用next执行。不需要再写回调函数了。
- 控制流管理:改善代码运行流程。
- 部署Iterator:使用该函数可以在任意对象上部署Iterator接口。
- 作为数据结构:看作数组结构。
12.12 async.await
-
Generator 函数的语法糖,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。
-
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
//一般是和promise接口调用的时候使用,可以简化代码 async function xx() { const data = await $http.get('...'); }
12.13 class
类的定义
class Foo {
constructor(x,y) {
this.x = x;
this,y = y;
}
add() {
return this.x + this.y;
}
}
var f = new Foo(1,2);
console.log(f.x); // 1
console.log(f.add()); //3
类的继承
class Bar extends Foo {
constructor(x,y,z) {
super(x,y);//必写!继承父类的属性和方法
this.z = z;
}
addAll() {
return super.add() + this.z;
}
}
var b = new Bar(1,2,3);
console.log(`${b.x} , ${b.z}`); //1 , 3
console.log(b.addAll());//6
12.14 proxy
Proxy ( 代理 ) 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
var proxy = new Proxy(target, handler);
//target:要拦截的目标
//handler:定制拦截行为
13.框架
13.1 MVC/MVP/MVVM
- MVC :模型,视图,控制器
-
MVP:模型,视图,表示器
-
MVVM:模型,视图,视图数据层
实现了双向绑定,这样VM的内容回实时展现在View层。
作为开发者主要维护和处理VM层,就将V和M完全解耦。
13.2 Vue/React/Angular
- Vue对比Angular
- Angular的学习成本高,增加了Dependency Injection特性,Vue提供的API都比较简单。
- 在性能上,Angular依赖对数据做
脏检查
,watcher越多越慢。(脏检查: 在angular中,数据绑定到html中后,这个数据改变了,需要检查刷新,这就触发了脏检查 ) - Vue的优化更好。Vue.js使用基于依赖追踪的观察并且使用异步队列更新。所有的数据都是独立出发的,对于庞大的应用来说,这个优化差异还是比较明显的。
- Vue对比React
- React依赖虚拟DOM,会对渲染出来的结果做脏检查。
- Vue使用DOM模板,模板中提供了指令,过滤器等,可以方便操作DOM
14.Vue
14.1 核心
- 核心:双向数据绑定和组件化
14.2 Vue双向绑定
-
实现一个监听器:Observer,对数据对象进行遍历,包括子属性对象的属性,利用Object.defineProperty()对属性加上setter和getter,实时监听到数据的变化。(阅读源码可知道,object.defineProperty()对数组不行,所以在2.x版本的源码中是重写了array的几个方法,将数据变为响应式加入到dep中,但是3.x的版本中是使用的 Proxy: 就没以上的问题,原生支持监听数组变化,并且可以直接对整个对象进行拦截)
-
实现一个解析器:Compile,解析Vue模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据变动就使用更新函数更新。
-
实现一个订阅者:Watcher,是Observer和Compile之间通讯的桥梁,主要任务是订阅Observer中属性变化的消息,收到属性值变化的消息时候触发Compile中对应的更新函数。
-
实现一个订阅器:Dep,用于收集Watcher,对监听器Observer和订阅者Watcher进行统一管理。
原理: -
通过建立虚拟dom树document.createDocumentFragment(),方法创建虚拟dom树。
-
一旦被监测的数据改变,会通过Object.defineProperty定义的数据拦截,截取到数据的变化。
-
截取到的数据变化,从而通过订阅—发布者模式,触发Watcher(观察者),从而改变虚拟dom的中的具体数据。的值,完成双向绑定
-
最后,通过更新虚拟dom的元素值,从而改变最后渲染dom树
14.3 computed和watch
- computed计算属性,依赖其他属性值,computed的值有缓存,当它依赖的值变化之后computed才会重新计算,执行computed中指定的方法,如果数据值没有变化但是调用computed时直接从缓存中取值,速度更快。
- watch观察监听数据,当监听的数据发生变化的时候会执行回调进行后续操作。
应用场景:
- 需要数值计算,依赖其他数据时就使用computed,可以利用其缓存特性,避免每次取值都重新计算。
- 需要在数据变化时执行异步或者开销大的操作时,使用watch,可以实现异步操作。
14.4 v-if/v-show
- v-if:条件渲染,条件为假时什么也不会渲染,当条件为真时才渲染。
- v-show:元素总是会被渲染,只是根据true和false让display属性进行切换。
v-if适用于在运行时很少改变条件,不需要频繁切换条件的场景。v-show适用于频繁切换条件的场景。
14.5 路由
vue-router 有 3 种路由模式:hash、history、abstract,对应的如下所示:
-
hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器;
其实现原理很简单,location.hash 的值就是 URL 中 # 后面的内容。比如下面这个网站,它的 location.hash 的值为 ‘#search’:
https://www.word.com#search
hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;
使用
hashchange
事件来监听 hash 值的变化,从而对页面进行跳转(渲染) -
history : 依赖 HTML5 History API 和服务器配置。具体可以查看 HTML5 History 模式;
其中做最主要的 API 有以下两个:
history.pushState()
和history.repalceState()
。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示:window.history.pushState(null, null, path); window.history.replaceState(null, null, path);
我们可以使用
popstate
事件来监听 url 的变化,从而对页面进行跳转(渲染),注意上面两个主要的api不会触发这个事件。 -
abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.
-
对比hash和history:通过history api,我们丢掉了丑陋的#,但是它也有个问题:不怕前进,不怕后退,就怕刷新,f5,(如果后端没有准备的话),因为刷新是实实在在地去请求服务器的,不玩虚的。在hash模式下,前端路由修改的是#中的信息,而浏览器请求时是不带它玩的,所以没有问题.但是在history下,你可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,会分分钟刷出一个404来。
14.6 生命周期
生命周期 | 描述 |
---|---|
beforeCreate | 组件实例被创建之初,组件的属性生效之前 |
Created | 组件实例已经完全创建,属性也绑定,但真实 dom 还没有生成,$el 还不可用 |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用 |
Mounted | el被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子 |
beforeUpdate | 组件数据更新之前调用,发生在虚拟 DOM 打补丁之前 |
Update | 组件数据更新之后 |
Activited | keep-alive 专属,组件被激活时调用 |
Deactivated | keep-alive 专属,组件被销毁时调用 |
beforeDestory | 组件销毁前调用 |
Destoryed | 组件销毁后调用 |
14.7 父子组件生命周期执行顺序
-
加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
-
子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
-
父组件更新过程
父 beforeUpdate -> 父 updated
-
销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
14.8 keep-alive
keep-alive是vue内置的一个组件,可以使被包含的组件保留状态,避免重新渲染,有以下特性:
- 一般结合路由和动态组件一起使用,用于缓存组件;
- 提供include和exclude属性,两者都支持字符串或者正则表达式,include:与之名称匹配的组件会被缓存;exclude:匹配的组件都不会被缓存;exclude的优先级更高
- 对应两个钩子函数actived和deactived,组件被激活就触发actived,组件被移除时,触发deactived函数;
14.9 data是函数
//vue的组件模板中,js部分,data是函数
data () {
return {...}
}
原因:组件是用来复用的,且js里对象是引用关系,如果组件中的data是一个对象,那么子组件里面的data都会互相影响,但是放在函数中,每个实例就可以维护一份被返回对象的独立拷贝,组件实例之间的data属性值不会相互影响;但是new Vue实例不会复用,所以直接是data:{}
14.10 v-model原理
操作表单的时候,使用v-model进行双向绑定,实际上相当于v-bind+v-on的结合;
- text/textarea: value属性 change事件
- checkbox/radio:checked属性 change事件
- select:value属性 change事件
14.11 自定义指令Vue.directive()
Vue.directive(指令名称,指令实现的函数)
Vue.directive('nm',function(el,binding,vnode) {
//el:指令所绑定的元素
//binding:一个对象,包含指令信息,打印出来看
//vnode:虚拟节点
el.style.color = binding.value
})
指令周期:
Vue.directive('my-directive', {
bind: function () {},
inserted: function () {},
update: function () {},
componentUpdated: function () {},
unbind: function () {}
})
14.12 axios
Axios是一个基于promise的http库,支持promise的api,且对于响应默认转换为json类型,安全性高,客户端支持防御[CSRF](#2.2 跨站请求伪造),默认不带cookies。ajax技术实现了网页的局部数据刷新,axios实现了对ajax的封装。
//vue中使用axios
axios.defaults.baseURL = 'xxx' //接口的根路径
//request
axios.interceptors.request.use((config)=>{
console.log(config);
//将token绑定在请求数据的头部,这样服务器可以有选择的返回数据,只对有效的请求返回数据
config.headers.Authorization = window.sessionStorage.getItem("token");
return config;
})
//response
axios.interceptors.response.use(config =>{
return config;
})
Vue.prototype.$http = axios; //$http是axios别称
//使用示例----------------
this.$http.put()/get()/post()/delete()
14.13 SPA
SPA:single-page-application,在页面初始化的时候加载相应HTML、JS和CSS。一旦加载完成,页面不会再因为操作而重新加载或者跳转,取而代之的是使用路由机制实现页面的改变。
- 优点:体验好,快,避免不必要的跳转和重复渲染,服务器压力也小;前后端分离;
- 缺点:初次加载耗时太多(因为加载全部的资源);前后进退由路由机制控制,不是浏览器的前后功能;SEO难度更大(所有的内容都在一个页面中动态管理)
14.14 Virtual DOM
虚拟 DOM 的实现原理主要包括以下 3 部分:
- 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
- diff 算法 — 比较两棵虚拟 DOM 树的差异;
- patch 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
Diff算法
对dom树同一层节点进行对比,将算法复杂度降低到o(n);
- 优点:保证性能下限;无需手动操作dom,因为MVVM的数据双向绑定;跨平台。
- 缺点:无法进行极致优化
14.15 Vue中的key原理
key是vue中vnode的唯一标记,通过key,diff操作更加准确快速
Vue的diff过程是:oldCh 和 newCh 各有两个头尾的变量 oldStartIndex、oldEndIndex 和 newStartIndex、newEndIndex,它们会新节点和旧节点会进行两两对比,即一共有4种比较方式:newStartIndex 和oldStartIndex 、newEndIndex 和 oldEndIndex 、newStartIndex 和 oldEndIndex 、newEndIndex 和 oldStartIndex,如果以上 4 种比较都没匹配,如果设置了key,就会用 key 再进行比较,在比较的过程中,遍历会往中间靠,一旦 StartIdx > EndIdx 表明 oldCh 和 newCh 至少有一个已经遍历完了,就会结束比较。
- 更准确:因为带 key 就不是就地复用了,在 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。
- 更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快。
14.16 Vue通信
-
props:父组件通过属性绑定将值传递给子组件,子组件使用props数组进行接收;
单向传递,父组件当前属性值更改,会影响子组件,反之不会。**但是如果传递的是引用类型(比如数组),父子组件中该数据变化都会互相影响。**可以使用深拷贝解决。
<div id="app"> <hello-world :title='msg' alter='其他' ></hello-world> </div> //然后在子组件上使用props接受title const helloWorld = { data:function(){ return {} }, props:['title','alter'], template:`<div>父组件给我传递的东西{{title}}</br>我自己的数据{{text}}` }
-
e m i t : emit: emit:emit方法传入事件的名称和参数(可以多个)。然后在父组件上使用v-on(@事件名称)监听,参数一个的时候,使用$event接受,参数多个使用arguments数组接受。
<div id="app"> <hello-world @text-add="handle(arguments)"></hello-world> </div> const hellowWorld = { data:function(){return {}}, template:`<button @click = '$emit("text-add",2,"hhh")'></button>` }
-
EventHub:组件之间数据交互;通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级
var eventHub = New Vue(); //事件的开启与销毁 eventHub.$on('name',(数据)=>{...});//写在指定组件的mounted周期 eventHub.$off('name'); //事件的触发 eventHub.$emit('name',数据)//写在指定组件的methods里
-
Vuex:适用于 父子、隔代、兄弟组件通信
-
a t t r s / attrs/ attrs/listeners: 仅仅是传递数据 的时候,使用Vuex太复杂,就使用 a t t r s / attrs/ attrs/listeners,
$attrs:包含绑定在子组件上,但是没有在props声明的属性
l i s t e n e r s : 包 含 了 父 作 用 域 中 的 ( 不 含 . n a t i v e 修 饰 器 的 ) v − o n 事 件 监 听 器 ( 非 原 生 事 件 ) 。 它 可 以 通 过 v − o n = " listeners: 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器(非原生事件)。它可以通过 v-on=" listeners:包含了父作用域中的(不含.native修饰器的)v−on事件监听器(非原生事件)。它可以通过v−on="listeners" 传入内部组件 。
<com-child :foo='foo' :boo='boo' :title='title'></com-child> //子组件中 props:['foo'],//porps里面只有foo,所以$attrs里面是boo,title属性值,$attrs可以直接在子组件使用,也可以使用v-bind="$attrs"继续传给下一个子组件 inheritAttrs: false,//配合使用!
-
provide/inject
祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量 ; 使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
provide 和 inject 绑定并不是可响应的。这是刻意为之的 ,就是说provide中的属性更改后,inject里面的值不会更新。 传入了一个可监听的对象,那么其对象的属性还是可响应的。
//a.vue 父组件 export default { provide: {name:'a-name'}, //下面这种可以响应 provide () { return { NAME: this } }, methods:{ upprovide(){ this.asideW = '500px'; // 修改 属性值得变化,可以传递到 子孙后代的任意组件 同时响应变化 } } } //b.vue 子孙组件 export default { inject: ['name','NAME'], mounted () { console.log(this.name);//a-name }, methods: { upprovide(){ //这里修改之后父也会响应数据的变化 this.NAME.asideW = '200px'; } } }
-
p a r e n t / parent/ parent/children/$roo/ref : 无法在跨级或兄弟间通信。
p a r e n t / parent/ parent/children:访问父, this. p a r e n t 查 找 当 前 组 件 的 父 组 件 / 访 问 子 实 例 , t h i s . parent查找当前组件的父组件 /访问子实例, this. parent查找当前组件的父组件/访问子实例,this.children查找当前组件的直接子组件,可以遍历全部子组件
this. r o o t 查 找 根 组 件 , 并 可 以 配 合 root查找根组件,并可以配合 root查找根组件,并可以配合children遍历全部组件
ref:普通的dom上使用指向的是dom元素,在子组件上使用指向子组件 ,this.$ref.name 访问指定名称的组件
//childred export default { data () { return {name:'children-title'} }, methods: { say() { console.log('hello') } } } //parent <template> <com-a ref='comA'></com-a> </template> <script> export defualt { mounted () { const comA = this.$ref.comA; console.log(comA.name);//√ comA.say();//√ } } </script>
14.17 Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)
只有mutations可以修改state中的数据
let store = new Vue.Store({
state : {},//全局数据,使用mapState读取数据
getters : {},//类似computed,使用mapGetters
mutations : {},//同步方法,更改state数据,mapMutations
actions : {}//异步方法,驱动mutations操作,this.$store.dispatch('actionName')state
})
vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,****具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。****
14.18 Vue SSR
服务端渲染:将同一个组件渲染为服务端的HTML字符串,将他们直接发送到浏览器,最后将这些静态标记激活为客户端上可以交互的应用程序。
- 优点:更好的SEO;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间;
- 缺点:更多的开发条件限制;更多的服务器负载。
14.19 Vue优化
查看详细解答看链接~
14.20 Vue3.0更新
-
监测机制的改变
vue3.0 将带来基于代理 Proxy 的 observer 实现,提供全语言覆盖的反应性跟踪。这消除了 Vue 2 当中基于 Object.defineProperty 的实现所存在的很多限制:
·只能监测属性,不能监测对象
·检测属性的添加和删除;(由全局api完成)
·检测数组索引和长度的变更;
·支持 Map、Set、WeakMap 和 WeakSet。
-
模板
模板方面没有大的变更,只改了作用域插槽,2.x 的机制导致作用域插槽变了,父组件会重新渲染,而 3.0 把作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提升了渲染的性能。
-
对象式的组件声明方式
3.0 修改了组件的声明方式,改成了类式的写法,这样使得和 TypeScript 的结合变得很容易。
15.工程化
15.1 git/svn
- git:四大区域:工作区,暂存区,本地版本库,远程仓库
-
git工作流程:
a) 在工作目录中修改某些文件
b) 对修改后的文件进行快照,然后保存到暂存区域
c) 提交更新,将保存在暂存区域的文件快照永久转储到Git目录中
-
常用指令
a)
git config
:设置用户名、邮箱等配置文件b)
git init
:创建仓库c)
git branch
:查看当前分支d)
git checkout
:切换分支e)
git status
:查看仓库的状态f)
git diff 文件名
:与上次相比修改了哪些内容git diff commitA commitB
:对比两次commit之间的差异g)
git add 文件名
:将添加的文件放到暂存区中h)
git commit -m “注释”
:将暂存区的内容提交到本地仓库i)
git clone 远程仓库地址
:将远程仓库克隆到本地(没有本地仓库时)j)
git pull 远程仓库地址
:将远程 repository 里新的 commit 数据(如有的话)下载过来,并且与本地代码merge。(有本地仓库时)k)
git fetch 远程仓库地址
:相当于是从远程获取最新版本到本地,不会自动merge -
与SVN的区别
a) Git是分布式的,SVN是集中式的(Git操作处理速度快,不依赖网络)
b) Git有强大的分支管理功能,而SVN较好的权限管理功能。
SVN
- 优点:管理方便,逻辑清晰,符合一般思维;易于管理,集中式更加保障安全;代码一致性高;适合开发人数不多的项目;
- 缺点:服务器压力大,数据库容量暴增;不能连接到服务器时不能工作;不适合开源开发。
Git
- 优点:适合分布式开发;公告服务器和数据量不大;速度快、灵活;任意两个开发者之间可以容易解决冲突;支持离线工作;
- 缺点:学习周期长;不符合常规思维;代码保密性差,clone之后源码就暴露了;
15.2 git rebase–git merge
git实现合并的两种方法;git rebase
:复位基底,将两个分支融合成一个新的线性提交;git merge
,把本地代码和取得的远程仓库代码合并,会生成一个新的节点,之前的提交会分开显示。
15.3 git revert
如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法。比如,想要撤销版本二,但又不想影响版本三的提交,就可以用 git revert
命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。
15.4 git reset
如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法。
git add
过程中提交了不想提交的文件,可以使用git reset filename
将文件从暂存区删除。
git reset和 git revert:
两个命令的目的是一样的,但是做法不一样,revert会以创建新的commit方式去撤销commit,可以保留之前的commit历史。
15.5 git pull
git pull = git fetch + git merge
拉取远程分支上的代码并合并到本地分支,目的是消除冲突
git pull --rebase = git fetch + git rebase
15.6 fork
-
fork:对仓库的克隆,克隆一个仓库并且允许对该仓库进行改变,但是不会影响原始项目;一般适用于更改别人的项目,做贡献,或者使用别人的项目开始项目。
eg : 在github上发现别人项目的bug,可以fork+pull request对项目进行修复,当拥有者认可之后会更新到原始项目中去。
-
Clone:克隆项目到本地。
-
Branch: 是一种机制,用于处理单一存储仓库中的变更,并最终目的是用于与其他部分代码合并。
15.7 Babel
babel是转译器,把同种语言的高版本规则翻译成低版本规则
和编译器类似,babel的转译过程也分为三个阶段:parsing、transforming、generating(解析,转换,生成),以ES6代码转译为ES5代码为例,babel转译的具体过程如下:ES6代码输入 ==》 babylon进行解析 ==》 得到AST==》 plugin用babel-traverse对AST树进行遍历转译 ==》 得到新的AST树==》 用babel-generator通过AST树生成ES5代码
15.8 Webpack
webpack是一个前端开发打包工具。将所有的资源都看作模块,可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分隔,等需要时再异步加载。通过 loader的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、AMD 模块、ES6 模块、CSS、图片、JSON、Coffeescript、LESS 等。
Gulp和webpack两者区别:
侧重点不同:Gulp侧重于前端开发的整个过程控制。例如刷新页面,雪碧图,压缩js等;Webpack侧重于模块打包,将资源都看作模块,使用loader和plugins对资源进行处理。
15.9 模块化发展
解决项目中全局变量被污染问题;开发效率高;方便维护代码和复用;解决文件的依赖问题,不用在意文件之间引用时候的顺序。
15.10 RequireJS
RequireJS是js模块加载器。
- 实现js文件的异步加载,避免网页失去响应
- 管理模块之间的依赖性,便于代码维护和编写
- 基于AMD模块化机制,让前端代码实现模块化;
main.js文件只要是加载RequireJS的配置项:
- baseUrl:模块默认加载路径
- paths:自定义模块加载路径
- shim:定义模块之间的依赖关系
16.计算机基础
16.1 操作系统
-
四个特性
- 并发:并发指宏观上在一段时间内可以同时运行多个程序。并行指同一时刻能运行多个指令。
- 共享:系统中的资源可供内存中多个并发执行的进程共同使用
- 虚拟:把一个物理实体变成若干个逻辑实体
- 异步:进程的执行不是一次性的,而是走走停停
-
进程与线程
- 进程:资源分配和调度的的基本单位
- 线程:独立调度的最小单位
- 联系: 一个程序至少有一个进程,一个进程至少有一个线程。 一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
- 进程通信:进程间传输信息。方式有管道,消息队列,信号量,共享存储(允许多进程共享一个给定的存储区),套接字
-
死锁
- 概念:计算机系统中,如果系统的资源分配策略不当,就会导致进程因为竞争资源不当产生死锁。
- 原因:系统资源不足;进程推进顺序不合理;资源分配不当
- 导致的必要条件:
- 互斥条件:一个资源每次只能被一个资源使用
- 请求与保持:1个进程因为请求而阻塞,对已经获取到的资源保持不放
- 不剥夺条件:进程已经获取的资源,在没有使用完之前不可以剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系;
-
内存管理
-
块式管理
把主存分为一大块、一大块的,当所需的程序片断不在主存时就分配一块主存空间,把程序片断载入主存,就算所需的程序片度只有几个字节也只能把这一块分配给它。这样会造成很大的浪费,但易于管理。
-
页式管理
把主存分为一页一页的,每一页的空间要比一块一块的空间小很多,显然这种方法的空间利用率要比块式管理高很多。
-
段式
把主存分为一段一段的,每一段的空间又要比一页一页的空间小很多,这种方法在空间利用率上又比页式管理高很多,但是也有另外一个缺点。一个程序片断可能会被分为几十段,这样很多时间就会被浪费在计算每一段的物理地址上
-
段页式管理(最常用)
结合了段式管理和页式管理的优点。把主存分为若干页,每一页又分为若干段。
-
17.数据库
17.1 sql查询语句
//基本查询
SELECT name,age FROM table01; //检索指定列
selct * FROM table; //检索所有列
SELECT DISTINCT year FROM table;//检索不同的行,做集合或者说滤重
SELECT name FROM table LIMIT 5;//返回的结果不多于5行
SELECT name FROM table LIMIT 5,5;//从第五行开始检索,检索出的结果不多于5行
SELECT name FROM table ORDER BY name ASC;//检索出的结果用指定的列进行排序,排序规则是升序(升序是默认的,指定降序是DESC)
SELECT id,name FROM table ORDER BY id,name;//检索结果先用id排序,再在同id上用name再排序
SELECT age FROM table ORDER BY age DESC LIMIT 1;//通过排序和LIMIT可以寻找最大最小值,当然也可以使用sql里面的max min方法
//数据过滤
where = <> != < <= > >= BETWEEN IN NOT LIKE
SELECT NAME,AGE FROM TABLE WHERE NAME='ASTER' AND/OR AGE<=20;//条件查询
SELECT ID FROM TABLE WHERE ID<>1000;//不等于
SELECT AGE FROM TABLE WHERE AGE BETWEEN 5 AND 20 或者 SELECT AGE FROM TABLE WHERE AGE (NOT) IN(5,20);//范围
SELECT NAME FROM TABLE WHERE ID IS NULL;//空值
SELECT name from tab where name (not) like 'a%';//搜索列中的指定模式,like后面的东西是指定模式。该句表示搜索name以a开头的列
//pattern指定模式的写法
//%通配符 :%表示0或多个字符
'a%' --- 以a开头 a ax axy axyz ...
'%a' --- 以a结尾 a xa xya xyza ...
'%a%' --- 包含a a xa ya xay ...
//_ 通配符:_表示单个字符
'_空调' --- X空调
'__空调' --- XY空调
//正则 REGEXP
select name from tab where name REGEXP '表达式'
//创建计算字段
//Concat
SELECT CONCAT(id,'--',name) FROM tab;//检索出的结果是 字段名CONCAT(id,'--',name):结果id--name
//AS使用别名
SELECT CONCAT(id,'--',name) AS title FROM tab;//字段名 title : 结果id--name
//执行算术计算 + - * /
select num*price as money from tab;
//使用内置函数
AVG() COUNT() MAX() MIN() SUM()
//组合 GROUP BY
//过滤分组 HAVING
SELECT id,COUNT(*) AS num FROM tab GROUP BY id HAVING COUNT(*) >=2; //过滤出条数大于等于2的分组
//使用子查询 组合多个查询语句
select name from tab1 where age in (select age from tab2 where age=12)
sql语句顺序
select .. from .. where .. group by .. having .. order by .. limit ..
17.2 MySQL
-
索引:帮助MySQL高效获取数据的数据结构
-
创建索引:
CREATE INDEX
为给定图表创建索引 -
索引结构分类:B+Tree HASH 等值查询使用Hash,范围查询使用B+
-
B+Tree索引:平衡多叉树。与红黑树比较有下面的特点:
- 更少的查找次数:平衡树查找的时间复杂度等于树高h,h = logdN,d为每个节点的出度。红黑树的出度为2,B+的出度一般都很大。所以红黑树的树高也就更大,需要进行查找的次数也更多。
- 利用磁盘预读特性:为了减少磁盘IO,磁盘一般不是严格按需读取,而是选择预读取。在预读过程中磁盘会按顺序读,需要时间很少,速度很快。同时数据库系统将索引的一个节点设置为一页大小,因此每次io读取就会载入一个节点。
-
-
存储引擎:
-
InnoDB:是MySQL的默认事务型存储引擎,只有它不满足时才会使用其他的。
-
MyISAM:设计简单,数据紧密存储,对于只读数据或者表比较小,可以容忍修复操作,可以使用它,不支持事务,不支持行级锁,只能对整表加锁。读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入
InnoDB MyISAM 事务 事务型,可以使用Commit和Rollback 非事务型 并发 支持行级锁 支持表级锁 外键 支持 不支持 备份 支持在线热备份 不支持 崩溃恢复 崩溃后损坏概率低 崩溃后损坏概率高,恢复速度慢 其他特性 支持压缩表和空间数据索引
-
-
事务
- 事务是由一步或者几步数据库操作序列组成逻辑执行单元,这些操作要么全部执行,要么全部不执行。一般是增删改操作。(区分程序和事务:一段程序种包含多个事务)
- 特点:
- 原子性:事务中最小的执行单位
- 一致性:事务执行的结果,必须是使得数据库从一个一致性状态,变到另一个一致性状态;
- 隔离性:各个事务执行互不干扰。
- 持续性:持久性,事务一旦提交,对数据做的更改都会被记到永久存储器(物理数据库)
-
并发一致性问题
在并发环境下事务的隔离性很难保证,因此会出现并发一致性问题:1)丢失修改 2)读脏数据 3)不可重复读 4)幻影读
-
封锁
行级锁和表级锁
封锁类型:
读写锁 【1】排他锁 x锁,写锁 【2】共享锁 S锁,读锁
意向锁
封锁协议:
- 一级:事务T要修改数据A时加上X锁,直到T结束才释放,解决丢失修改问题。
- 二级:一级基础上,要求读数据A加上S锁,读完释放,解决读脏数据问题。
- 三级:二级基础上,读取数据A加上S锁,事务结束释放,解决不可重复读的问题。
-
隔离级别
- 未提交读:事务中的修改,即使没有提交,对其他事务也是可见的。
- 提交读:事务中的修改,必须提交后,对其他事务才可见。
- 可重复读:保证在同一个事务中多次读取同样数据结果一致。
- 可串行化:强制事务串行执行。
-
关系型数据库设计理论
- 函数依赖:A->B表示B函数依赖A
- 异常:
- 冗余数据:数据库表中相同数据出现两次
- 修改异常:修改一个记录中的数据,相关的记录中没有同步修改
- 删除异常:删除一个信息,丢失了其他的
- 插入异常:无法插入信息
- 范式 ??
- 第一范式:属性不可分。【原子性,字段不可再分割】
- 第二范式:每个非主属性完全函数依赖于键码,通过分解实现。【完全依赖,没有部分依赖】
- 第三范式:非主属性不传递函数依赖于键码。【没有传递依赖,保持每列都跟主键直接相关】
-
ER图
实体-关系图,有三个组成部分:实体,属性和关系
实体-数据表,属性-数据列,关系-数据表与数据表之间的关系
-
设计表应考虑的因素
·作用是什么/至少包含的数据,这些数据属于哪些实体对象
·E-R模型
·考虑每一列的数据类型
·允许为空和默认值,原则是尽量少允许为空
·主键问题
·约束和规则
·外键问题
·考虑是否使用索引
18.数据结构
排序算法
时间复杂度 O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n)
19.代码
19.1 call/apply/bind
call 和 apply是 Function 对象的原型方法,它们能够将特定函数当作一个方法绑定到指定对象上并进行调用,call传递的参数是多个参数,apply传递的参数是数组元素
bind返回一个绑定了this的函数.
function.call(thisobj, args...);
function.apply(thisobj, [args]);
function.bind(thisobj,args...);//args可以传递部分
//将函数function绑定在thisobj上使用。
Function.prototype.mycall = function (obj){
console.log('this is mycall')
var obj = obj || window;
obj.fn = this;
var args = [...arguments].slice(1);//调用call的时候,第一个参数是this对象,后面的才是传递的参数
var result = obj.fn(...args);
delete obj.fn;
return result;
}
function add(x,y) {
return x+y;
}
console.log(add.mycall(this,10,20));//this is my call 30
Function.prototype.myapply = function (obj) {
console.log('this is my apply');
var obj = obj || window;
obj.fn = this;
var result = null;
if(arguments[1].length != 0) {
result = obj.fn(...arguments[1])
}else {
result = obj.fn();
}
delete obj.fn;
return result;
}
console.log(add.myapply(this,[15,25]))//this is my apply 40
Function.prototype.mybind = function (obj) {
console.log('this is mybind')
if(typeof this != 'function') {
throw new TypeError('error type');
}else{
var _this = this;
var args = [...arguments].slice(1);
return function F(){
if(this instanceof F){
return new _this(...args, ...arguments);
}else{
return _this.apply(obj,args.concat(...arguments));
}
}
}
}
var myadd = add.mybind(this,10)//args可以只传递部分
console.log(myadd(20))
19.2 防抖节流
防抖:将几次操作合并为一次。
//一般是设置一个计时器,事件触发之后,不立刻执行,在延迟时间之后再触发。如果时间内被触发计时器就重新开始计时。如果时间内没有再次触发滚动事件,那么就执行函数。
function debounce(fu,delay) {
//计时器
let timer = null;
return function() {
// this 指向不变以及依旧能接受到 e 参数。
let context = this;
let args = arguments;
if(timer) {clearTimeout(timer);}
timer = setTimeout(() => {
fn.apply(context,args)
},delay)
}
}
节流:连续触发函数,n秒内只会执行一次
//1==时间戳版本 2==定时器版本
function throttle(type,fn,delay) {
if(type==1) {var prev = 0;}
else if(type==2) {var timer = null;}
return function() {
let context = this;
let args = arguments;
if(type==1){
let now = Date.now();
if(now-prev > delay){
fn.apply(context,args);
prev = now;
}
}else if(type==2){
if(!timer){
timer = setTimeout(()=>{
timer = null;
fn.apply(context,args)
},delay)
}
}
}
}
19.3 Ajax
let xhr = new XMLHttpRequest();//实例化
xhr.open(method, url, async);//初始化
xhr.send(data);//发送请求
xhr.onreadystatechange = () => {//获取请求结果
if(xhr.readyStatus === 4 && xhr.status === 200) {
console.log(xhr.responseText;
}
}
19.4 设计模式
订阅-发布者模式:面试考
vue的emit on就是这个模式
19.5 快排
19.6 扁平化数组
Array.prototype.flat():该方法会按照指定的深度遍历递归数组,并将所有的元素与遍历到的数组元素合并为新的数组返回。该方法不会修改原有的数组
var mflat = function(arr, depth) {
let res = [],
depthArg = depth || 1,
depthNum = 0,
flatMap = (arr) => {
arr.map((element, index, array) => {
// if(Object.prototype.toString.call(element).slice(8, -1) === 'Array'){
if(Array.isArray(element)){
if(depthNum < depthArg){
depthNum++;
flatMap(element);
}else{
res.push(element);
}
}else{
res.push(element);
if(index === array.length -1) depthNum = 0;
}
});
};
flatMap(arr);
return res;
};
let arr = [1,2,3,[4,5,[6,7]]]
arrNew = mflat(arr,2);//[1,2,3,4,5,6,7]
flat()默认只会“拉平”一层 ,默认值是1,想要将多层嵌套的数组变成一维,可以使用Infinity
如果原数组有空位,flat()方法会跳过空位。
let arr = [1,2,[3,[4,5]]];
arrNew1 = arr.flat();//[1,2,3,[4,5]]
arrNew2 = arr.flat(Infinity);//[1,2,3,4,5]
19.7 回文字符串
-
双指针:
let left=0,right=len-1; while(left<right){ if(s[left] != s[right]) return false; left++; right--; }
19.8 一些算法总结
- 数组:出的功能:shift pop 入的功能:unshift push
一维数组,排序遍历,辅助数组,交换位置,二分查找(使用二分查找的之后时间复杂是log)
二维数组,行号和列号关系
-
字符串:
转成数组(split()),利用数组方法
辅助字符串
字符串方法 indexOf() lastIndexOf() replace()
统计字符串中各个字母
arr = Array(26).fill(0); for(let i=0; i<len; i++) { arr[s.charCodeAt(i) - 97] ++;//默认字符串里面都是小写字符 }
-
链表:
// Definition for singly-linked list. function ListNode(val) { this.val = val; this.next = null; } //统计链表的长度 node = head; while(node){ len++; node = node.next; } //一般程序中,不要损坏原有的链表,先将链表进行备份,在备份的链表上进行修改 let dummy = new ListNode(-1); dummy.next = head; //在dummy上操作... ... return dummy.next;
单向链表,循环,递归( 最先调用的函数会在递归过程中最后被执行,而最后调用的会最先执行 )
//翻转链表head newl=null; while(head){ let next = head.next; head.next = newl; newl = head; head = next; } //寻找链表的中点,使用快慢指针 slow=head,fast=head while(fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; } //环形链表,同样使用快慢指针,终究是会相遇的
-
树
//Definition for a binary tree node. function TreeNode(val) { this.val = val; this.left = this.right = null; }
三种遍历方式,宽度优先遍历
//二叉树的深度 let query=[root],n=0; while(query.length){ let arr=[]; while(query.length){ let node = query.shift(); if(node.left) arr.push(node.left); if(node.right) arr.push(node.right); } query=arr; n++; } //中序遍历 var inorderTraversal = function(root) { let curr=root,stack=[],list=[]; while(curr!=null || stack.length) { while(curr!=null){ stack.push(curr) curr=curr.left;//添加左子结点 } curr=stack.pop(); list.push(curr.val); curr=curr.right; } return list };
-
栈和队列
stack堆栈,先进后出。进栈 push 出栈 pop
queue队列,先进先出, 只允许在表的前端(front)进行删除操作shift,而在表的后端(rear)进行插入操作 push
-
递归
排序
回溯法
动态规划 dp=new Array(); 然后寻找dp[i]与其他的关系
// if(Object.prototype.toString.call(element).slice(8, -1) === 'Array'){ if(Array.isArray(element)){ if(depthNum < depthArg){ depthNum++; flatMap(element); }else{ res.push(element); } }else{ res.push(element); if(index === array.length -1) depthNum = 0; } }); };
flatMap(arr);
return res;
};
let arr = [1,2,3,[4,5,[6,7]]]
arrNew = mflat(arr,2);//[1,2,3,4,5,6,7]
**flat()默认只会“拉平”一层** ,默认值是1,想要将多层嵌套的数组变成一维,可以使用Infinity
**如果原数组有空位,flat()方法会跳过空位。**
let arr = [1,2,[3,[4,5]]];
arrNew1 = arr.flat();//[1,2,3,[4,5]]
arrNew2 = arr.flat(Infinity);//[1,2,3,4,5]
### 19.7 回文字符串
1. 双指针:
```js
let left=0,right=len-1;
while(left<right){
if(s[left] != s[right]) return false;
left++;
right--;
}
19.8 一些算法总结
- 数组:出的功能:shift pop 入的功能:unshift push
一维数组,排序遍历,辅助数组,交换位置,二分查找(使用二分查找的之后时间复杂是log)
二维数组,行号和列号关系
-
字符串:
转成数组(split()),利用数组方法
辅助字符串
字符串方法 indexOf() lastIndexOf() replace()
统计字符串中各个字母
arr = Array(26).fill(0); for(let i=0; i<len; i++) { arr[s.charCodeAt(i) - 97] ++;//默认字符串里面都是小写字符 }
-
链表:
// Definition for singly-linked list. function ListNode(val) { this.val = val; this.next = null; } //统计链表的长度 node = head; while(node){ len++; node = node.next; } //一般程序中,不要损坏原有的链表,先将链表进行备份,在备份的链表上进行修改 let dummy = new ListNode(-1); dummy.next = head; //在dummy上操作... ... return dummy.next;
单向链表,循环,递归( 最先调用的函数会在递归过程中最后被执行,而最后调用的会最先执行 )
//翻转链表head newl=null; while(head){ let next = head.next; head.next = newl; newl = head; head = next; } //寻找链表的中点,使用快慢指针 slow=head,fast=head while(fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; } //环形链表,同样使用快慢指针,终究是会相遇的
-
树
//Definition for a binary tree node. function TreeNode(val) { this.val = val; this.left = this.right = null; }
三种遍历方式,宽度优先遍历
//二叉树的深度 let query=[root],n=0; while(query.length){ let arr=[]; while(query.length){ let node = query.shift(); if(node.left) arr.push(node.left); if(node.right) arr.push(node.right); } query=arr; n++; } //中序遍历 var inorderTraversal = function(root) { let curr=root,stack=[],list=[]; while(curr!=null || stack.length) { while(curr!=null){ stack.push(curr) curr=curr.left;//添加左子结点 } curr=stack.pop(); list.push(curr.val); curr=curr.right; } return list };
-
栈和队列
stack堆栈,先进后出。进栈 push 出栈 pop
queue队列,先进先出, 只允许在表的前端(front)进行删除操作shift,而在表的后端(rear)进行插入操作 push
-
递归
排序
回溯法
动态规划 dp=new Array(); 然后寻找dp[i]与其他的关系
插入,冒泡,归并和快速排序比较