# 前端开发知识点-基础篇
# 1 Cookie、Session、SessionStorage 和 LocalStorage
Cookie:服务器提供的一种用于维护会话状态信息的数据,通过服务器发送到浏览器,浏览器保存在本地的一种纯文本文件,当下一次有同源的请求时,将保存的 Cookie 数据添加到请求头部,发送给服务端。可以用来实现记录用户登录状态等功能。
Session:服务器为了保存用户状态而创建的一个特殊的对象。在浏览器第一次访问服务器时,服务器会创建一个 session 对象,该对象有一个唯一的 id,即 sessionid,服务器会把 sessionid 以 cookie 的形式发送给浏览器,当浏览器再次访问服务器时,会携带 cookie 在请求头,可以通过 cookie 中的 sessionid 来访问 session 对象,可以实现在 http 无状态基础上实现用户状态管理。
Cookie 的特点:
- Cookie 数据存放在客户端上。
- Cookie 是非安全的,由于存在本地,有被盗取的可能。
- Cookie 保存的数据不能超过 4K。
- Cookie 始终在同源的 HTTP 请求中携带。
如何设置 Cookie:
- 服务端:使用 Set-Cookie 的响应头部,包含 5 个属性值 expires、 domain、path、secure 和 httponly,分别代表过期时间、域名、路径、安全传输、是否禁用客户端 js 脚本访问。
- 客户端:通过 JS 脚本,例如 document.cookie
Cookie 和 Session 和区别:
- Cookie 存放在客户端,Session 存放在服务端。
- Cookie 是非安全的,考虑安全应该使用 Session
- 访问增多时,服务器压力比较大,考虑使用 Cookie
- 单个 Cookie 保存的数据不能超过 4K
Cookie、SessionStorage 和 LocalStorage 的区别:
- Cookie 始终在同源的 HTTP 请求中携带。(即使不需要)
- Cookie 可以限制可访问的 path
- 存储大小:Cookie 存放数据不能超过 4k,WebStorage 可以达到 5M 或更大。
- 有效期不同:SessionStorage 只在当前浏览器窗口关闭前有效,LocalStorage 始终有效,用作持久化,Cookie 在设置的过期时间之前一直有效。
Cookie 常用场景:
- 保持用户登录状态
- 跟踪用户行为,记录用户选项
# 2 Http 和 Https 的区别
HTTPS 基本原理:客户端使用 HTTPS URL 访问服务端,要去服务端建立 SSL 连接,服务端接收到客户端请求后,会将网站的证书(携带公钥)返回给客户端,客户端和服务端开始协商 SSL 连接的安全等级,也就是加密等级,然后两者通过协商一致的安全等级,建立会话密钥,然后客户端通过网站的公钥来加密会话密钥,传给网站,服务端通过自己的私钥解密出会话密钥,通过会话密钥加密与客户端的通信。
- 安全性:HTTPS 是安全超文本协议,在 HTTP 基础上有更强的安全性,简单来说,HTTPS 是使用了 TLS/SSL 加密的 HTTP 协议。
- 申请证书:HTTPS 需要使用 CA 证书。
- 传输协议:HTTP 以明文形式传输数据,HTTPS 以加密形式传输数据。
- 端口号不同:一般来说,HTTP 协议的端口为 80,HTTPS 的端口为 443
- 连接方式:HTTP 的连接简单,是无状态的,HTTPS 在 HTTP 的基础上使用了 SSL 协议进行加密传输。
# 3 Http2.0 的特性
- 提升了访问速度
- 允许多路复用:允许同时通过单一的 HTTP/2 连接发送多重请求-响应信息。
- 二进制分帧:将所有的传输数据分割为更小的数据帧,并对它们进行二进制编码。
- 首部压缩
- 服务器端推送
# 4 OSI 七层模型
- 应用层:文件传输,常用协议 HTTP、STMP、FTP
- 表示层:数据格式化、代码转换、数据加密
- 会话层:建立和解除会话
- 传输层:提供端对端的接口,TCP/UDP
- 网络层:为数据包选择路由,IP/ICMP
- 数据链路层:传输带有地址的帧。
- 物理层:二进制的数据形式在物理媒体上传输数据。
# 5 TCP 和 UDP 的区别
- TCP 是面向连接的,UDP 是无连接的,即发送数据前不需要先建立连接。
- TCP 提供可靠的服务,无差错、不丢失、不重复、按序到达,UDP 尽最大努力交付。(大数据量使用 TCP)
- TCP 面向字节流,UDP 面向报文。(UDP 无拥塞控制,可能出现丢包)
- TCP 只能 1 对 1,UDP 支持 1 对 1 和 1 对多。
- TCP 首部较大为 20 字节,UDP 只有 8 字节。
# 6 TCP 三次握手和四次挥手
TCP 三次握手:(A 为客户端,B 为服务端)
- B 处于监听,A 向 B 发送连接请求报文 SYN=1,ACK=0,选择一个初始的序号 x
- B 收到连接请求报文,如果同意连接,则向 A 发送连接确认报文 SYN=1,ACK=1,确认号 ack=x+1,选择初始序号 y
- A 收到 B 的连接确认报文,向 B 发送确认报文 ACK=1,确认号 ack=y+1,序号为 x+1
- B 收到 A 的确认,连接建立。
三次握手的原因
第三次握手防止失效的连接请求到达服务器,让服务器错误打开连接。客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务端返回的确认,导致:客户端超时重传重新建立连接,这时就会出现 2 个 SYN 连接。如果有第三次握手,客户端会忽略服务端之后发送的对滞留连接请求的确认,不进行第三次握手,因此就不会打开连接。
TCP 四次挥手:
- A 发送连接释放报文 FIN=1,序号为 u
- B 收到后发出确认 ACK=1, ack=x+1, 序号为 v,此时 TCP 属于半关闭状态,A 不能发数据,B 能发数据。
- B 不需要连接时,发送连接释放报文 FIN=1,ACK=1,ack=u+1,序号为 w
- A 收到后发出确认 ACK=1,ack=w+1,序号为 u+1,进入 TIME-WAIT 状态,等待 2MSL(最大报文存存活时间)后释放连接。
- B 收到 A 的确认后释放连接。
# 7 HTTP 状态码
状态码按第一个数字分类,1 表示信息,2 表示成功,3 表示重定向,4 表示客户端错误,5 表示服务端错误。
常见状态码:101 切换协议、200 成功、301 永久重定向、302 临时重定向、304 未修改、400 请求无效、401 未认证、403 拒绝执行、404 未找到资源
200 和 304 的区别:
- 200 是请求成功,一般用于 GET 和 POST
- 304 是未修改,所请求的资源未修改,服务器返回此状态码时,不会返回任何资源,客户端通过缓存访问资源(协商缓存)。
# 8 HTTP 缓存机制
- 强缓存:返回状态码为 200,不会向服务端发送请求,直接从缓存取资源。相关字段有 pragma、expires、cache-control(cache-control 优先级更高,pragma 优先级最高)。
- 协商缓存:返回状态码为 304,会向服务端发送请求,通过服务器告知缓存是否可用。相关字段有 Last-Modified/If-Modified-Since,Etag/If-None-Match
缓存流程:
- 缓存是否过期:未过期,则从缓存读取(强缓存),否则下一步。
- Etag 值:True,向服务端发送带 If-None-Match 的请求,否则继续判断 Last-Modified
- Last-Modified 为 True,向服务端发送带 If-Modified-Since 的请求,否则正式发送请求,相应后缓存协商。。(无缓存)
- 服务器根据 If-None-Match 和 If-Modified-Since 决策返回 200 还是 304,304 则从缓存读取(协商缓存),200 则走正常请求。
# 9 XSS 攻击和 CSRF 攻击
XSS 攻击:跨站脚本攻击,盗取 Cookie,在返回的 HTML 中嵌入 js 脚本,防范方法:用户输入检查(过滤特殊字符等)、设置 set-cookie 的 httponly 属性。
CSRF 攻击:跨站请求伪造,利用 Cookie,以用户的名义发送恶意请求。防范方法:验证码、检查 HTTPS 头部的 referer、使用 token。
# 10 HTTP 常见请求头
可以划分为:通用首部、请求首部、相应首部和实体首部
通用首部:
- Accept:可接受的响应内容类型
- Accept-Encoding:可接受的响应内容编码形式
- Accept-Language:可接受的响应语言列表
- Cache-Control:是否使用强缓存
- Pragma:一般来说指,是否使用强缓存
- Connection:连接类型(keep-alive)
- User-Agent:浏览器的身份标识字符串
- Content-Length:8 进制标识的请求体的长度。
- Content-Type:请求体的 MIME 类型,用于 POST 和 GET
- Host:服务器的域名及监听端口号,80 则可以省略
请求首部:
- cookie
- Etag/If-None-Match
- Last-Modified/if-Modified-Since 等
响应首部:
- set-cookie 等
# 11 HTTP 常见请求方法
- get:请求资源
- head:请求 header
- post:建立或修改资源。
- put:取代资源
- delete:删除指定资源
- connect:
- options:允许客户端查看服务端的性能
- trace:回显服务器收到的请求,用于测试和诊断
- patch:对 put 的补充,对已有资源局部更新。
# 12 输入 URL 到显示页面的过程
- 首先需要找到这个 url 域名的服务器 ip,首先会寻找缓存中的记录,如果没有则查找本地的 hosts 文件是否有记录,如果没有则进行下一步。
- DNS 解析:首先,客户端通过发送 DHCP 请求报文获取网关路由器的 IP 地址,然后通过 ARP 协议获取网关路由器的 MAC 地址,接着向网关路由器发送 DNS 查询报文,到达 DNS 服务器后,在 DNS 数据库中查询域名解析后的 IP 地址。
- 浏览器根据得到的 IP 地址及相应的端口号,构造一个 HTTP 请求报文,并将这个 HTTP 请求封装在一个 TCP 包中,依次经过传输层、网络层、数据链路层、物理层到达服务端,服务端解析这个请求来作出响应给浏览器。
- 浏览器解析响应内容并渲染页面,结束连接。(DOM 树和 CSSOM 树)
# 13 Websocket
WebSocket 是 HTML5 中的协议,支持持久连续,http 协议不支持持久性连接。Http1.0 和 HTTP1.1 都不支持持久性的链接,HTTP1.1 中的 keep-alive,将多个 http 请求合并为 1 个。
HTTP 的生命周期通过 Request 来界定,也就是 Request 一个 Response,那么在 Http1.0 协议中,这次 Http 请求就结束了。在 Http1.1 中进行了改进,有一个 connection:Keep-alive,也就是说,在一个 Http 连接中,可以发送多个 Request,接收多个 Response。但是必须记住,在 Http 中一个 Request 只能对应有一个 Response,而且这个 Response 是被动的,不能主动发起。
WebSocket 是基于 Http 协议的,或者说借用了 Http 协议来完成一部分握手,在握手阶段与 Http 是相同的。有 2 个相关的请求头,upgrade,connection。
upgrade:websocket
connection:upgrade
# 14 BOM 对象
浏览器对象,location、history 和 navigator
常用属性和方法:
- history:go、back、forward
- navigator:userAgent、cookieEnabled
- location:
- get 类型:href、search、hash、host、hostname、pathname、port、protocal
- set 类型:assgin(设置 url)、replace(设置 url,并且在 history 中移除)、reload
# 15 CORS 跨域请求的方式
cors:跨域资源共享,客服了 AJAX 只能同源使用的限制。
只要同时满足以下两大条件,就属于简单请求
- 请求方法为 head、get、post 之一
- 请求头只有:Accepet、Accpet-Language、Content-Language、Last-Event-ID、Content-Type 这五种,并且 Content-type 只有 application/x-www-form-unlencoded、multipart/form-data、text/plain 这三种。
对于简单请求,浏览器直接发出 CORS 请求,在请求头加上 Origin 字段,用来说明来自哪个源,服务器根据这个值决定是否同意此次请求,同意则返回响应,响应头多出几个字段(以Access-Control-开头),否则返回一个正常的 HTTP 响应,但请求头不包含 Access-Control-Allow-Origin 字段,抛出一个错误。
withCredentials 属性
CORS 请求默认不发送 Cookie 和 HTTP 认证信息,如果需要发送,一方面需要服务器同意,指定 Access-Control-Allow-Credentials 为 True,另一方面 ajax 请求要设置 withCredentials 属性为 true。此外,如果要发送 Cookie,Access-Control-Allow-Origin 就不能设置为星号,必须指定明确的、与明确网页一致的域名。同时,Cookie 依然遵循同源政策。
预检请求
对于复杂请求的 CORS 请求,会在正式通信前,增加一次 HTTP 查询请求,称为预检请求,浏览器先询问服务器,如果同意才会发出正式的 XMLHttpRequest 请求,否则就报错。
预检请求用的请求方法为 OPTIONS,请求头有 Origin、Access-Control-Request-Method、Access-Control-Request-Headers 这三个字段。
一旦服务器通过了预检请求,以后每次浏览器正常的 CORS 请求,都跟正常请求一样,会有一个 OrIgin 请求头字段,服务器响应请求头会带有 Access-Control-Allow-Origin。
# 16 CSS 盒模型
- 标准盒模型:box-sizing:content-box;width=content
- IE 盒模型:box-sizing:border-box;width=content+border+padding
- box-sizing:padding-box;width=content+padding
# 17 link 标签和 import 标签的区别
- link 属于 html 标签,@import 是 css 提供的。
- 加载时机:页面加载时,link 会同时加载,而@import 引用的 css 会等到页面加载结束后加载。
- 兼容性:@import 只有 IE5 以上才支持。
- 优先级:link 大于@import
# 18 transition 和 animation 的区别
- 大部分属性相同,都是随时间改变元素的属性值。
- transition 需要触发一个事件才能改变属性,而 animation 不需要触发任何事件。
- transition 为 2 帧,animation 可以一帧一帧。
# 19 Flex 布局
弹性布局,用来为盒状模型提供最大的灵活性。
划分:容器属性和元素属性
容器属性:
- flex-direction:主轴方向
- flex-wrap:换行规则
- flew-flow:上面两者结合。
- justify-content:主轴对齐方式
- align-items:交叉轴对齐方式
元素属性:
- order:排列顺序
- flex-glow:放大比例
- flex-shrink:缩小比例
- flex-basis:占据空间
- flex:上面三者的缩写
- align-self:允许元素与其它项目的对齐方式不一样,默认 auto,继承父元素的 align-item
# 20 BFC
BFC:块级格式化上下文,用于清除浮动,防止 margin 重叠等
BFC 是页面上的一个独立容器,子元素不会影响到外面,计算 BFC 的高度时,浮动元素也会参与计算。
会生成 BFC 的元素:
- float 不为 none 的元素
- position 为 fixed 和 absolute 的元素
- display 为 inline-block、table-cell、table-caption、flex、inline-flex 的元素。
- overflow 不为 visible 的元素
# 21 块元素和行元素
- 块元素:独占一行,并且有自动填满父元素,可以设置 margin 和 padding 以及高度和宽度
- 行元素:不会独占一行,width 和 height 会失效,并且在垂直方向的 padding 和 margin 会失效。
# 22 HTML5 和 CSS3 的新元素
- HTML5 新增元素:
- 新标签:8 个语义标签(header、section、footer、aside、nav、main、article、figure)、mark 高亮、progress 进度、新表单控件(calendar、data、time、email、url、search)、新的 input 类型(color、date、datetime、datetime-local、email)
- canvas 绘图,支持内联 SVG,支持 MathML
- 多媒体:audio、video、source、embed track
- 本地离线存储:manifest 配置文件
- web 存储:localStorage、SessionStorage
- 其它:web worker、websocket
- CSS3 新元素
- 边框: border-radius、box-shadow
- 背景:background-size、background-origin
- 文本效果:text-shadow、word-wrap、word-break 等
- 2D/3D 转换:transform
- 动画:animation
# 23 重绘和重排
DOM 的变化影响到了预算内宿的几何属性比如宽高,浏览器重新计算元素的几何属性,其他元素的几何属性也会受到影响,浏览器需要重新构造渲染树,这个过程称之为重排,浏览器将受到影响的部分重新绘制在屏幕上的过程称为重绘。
重绘和重排的原因:
- 添加或删除可见的 DOM 元素
- 元素尺寸位置的改变
- 浏览器页面初始化
- 浏览器窗口大小发生改变。
重排一定导致重绘,重绘不一定导致重排。
减少重排,提高性能的方法:
- 元素的多次样式修改合并成一次修改。
- 如需进行对 DOM 节点进行多次操作,先将其脱离文本流之后再进行多次操作。
- table 布局的渲染与普通 DOM 节点的操作相比,性能消耗更大,如果可以,尽量减少 table 布局的使用。
- 缓存常用的布局信息。
# 24 闭包
闭包:当一个嵌套的内部函数引用了外部函数的变量或者函数时,外部函数在执行时就产生了闭包。
典型的闭包:
- 将函数作为灵一个函数的返回值
- 将函数作为实参传给另一个函数调用
闭包特点:函数嵌套函数,内部函数引用外部函数的变量。
闭包的作用:
- 延长外部函数局部变量的生命周期,可以用于实现计数器。
- 可以形成变量的局部作用域,实现函数封装。
闭包的缺点:函数定义的变量和数据会一直存在内存函数中,不会被及时释放,容易导致内存泄漏。
# 25 类的创建和继承
类的创建:new 一个 function,在这个 function 中的 prototype 里面添加属性和方法
function Animal(name){
this.name = name || 'Animal';
//实例方法
this.sleep = function(){
console.log(this.name + "正在睡觉!");
}
//原型方法
Animal.prototype.eat = function(food){
console.log(this.name + "正在吃" + food);
};
}
类的继承:4 种方式
原型链继承(new 一个空对象,空对象指向 Animal,缺点是无法多继承)
function Cat(){ Cat.prototype = new Animal(); Cat.prototype.name = 'Cat'; }
构造继承(使用父亲的构造函数来增强子类实例,等于复制父亲的实例属性)
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; }
优点:可以多继承
缺点:只能继承实例属性和方法
实例集成和拷贝继承:
- 实例继承:为父亲实例添加新特性,作为子类实例返回
- 拷贝继承:拷贝父亲元素上的属性和方法
组合继承:构造继承和原型链继承的组合
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } Cat.prototype = new Animal(); Cat.prototype.constructor = Cat;
通过调用父类构造,继承父亲的属性并保留传参的优点,然后通过将父亲实例作为子类原型,实现函数复用。
特点:可以继承实例属性,也可以继承原型属性
缺点:调用了两次父类构造函数,生成了两份实例
寄生组合继承:通过寄生方式,砍掉父亲的实例属性
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } var Super = function(){}; Super.prototype = Animal.prototype; Cat.prototype = new Super();
最常用的方法:
Cat.prototype = Object.create(Animal.prototype);
# 26 promise、generator、async/await
promise:CommonJS 工作组提出的一种规范,目的是为异步编程提供统一接口。每一个异步任务返回一个 Promise 对象,该对象有一个 then 方法,允许指定回调函数。有三个状态:等待(pending)、已完成(resolved,又称 fulfilled)、已拒绝(rejected)。promise 必须实现 then 方法(可以说,then 就是 promise 的核心),而且 then 必须返回一个 promise,同一个 promise 的 then 可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致。then 方法接受两个参数,第一个参数是成功时的回调,在 promise 由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在 promise 由“等待”态转换到“拒绝”态时调用。同时,then 可以接受另一个 promise 传入,也接受一个“类 then”的对象或方法,即 thenable 对象。
使用举例:
func(){ return new Promise((resolve,reject)=>{ work().then(res=>{ this.data = res.data; resolve(); }).catch(error=>{ reject(error); }) }) }
promise 的用处
- 解决了回调函数的回调地狱问题,有时候我们的请求需要上一个请求返回的结果,会造成相互间回调函数的嵌套,使得代码的可读性和维护性很低。
- 让代码变得扁平,可读性更好,then 返回一个 promise,可以把 then 串起来,then 返回的 promise 装载了由调用返回的值。
- 在异步回调中,函数的执行栈与原函数分离开,导致外部无法抓住异常。在 promise 中我们可以使用 reject 捕获失败情况,和 catch 捕获执行异常。
- promise 只不过是一种更良好的编程风格。
promise 的缺点:
- 不设置回调函数,promise 内部抛出的错误,无法返回到外部。
- 处于 pending 状态时,无法得知进展到哪一个阶段。
async 和 await:
- async 函数返回一个 promise 对象,在没有 await 的情况下执行 async 函数,它会立即返回一个 promise 对象,并且,绝对不会注意后面语句的执行,await 关键字只能用在 aync 定义的函数内; await 可以用于等待一个 async 函数的返回值,如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。async/await 使得异步代码看起来像同步代码,使代码简洁,可读性更好,避免嵌套。
# 27 事件流
事件流:从页面接受事件的顺序,DOM2 级事件流包括下面几个阶段
- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
addEventListener:DOM2 级事件新增的指定事件处理程序的操作,这个方法接受三个参数,要处理的事件名,作为事件处理程序的函数和一个布尔值(true 则在捕获阶段调用事件处理程序,否则在冒泡阶段调用)。IE 只支持事件冒泡。
addEventListener 示例:
var op = document.getElementById("id"); op.addEventListener('click', function(e){ //do something }, false);
# 28 事件委托(代理)
事件委托:事件委托指的是,不在事件的发生地(直接 dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素 DOM 的类型,来做出不同的响应。
举例:最经典的就是 ul 和 li 标签的事件监听,比如我们在添加事件时候,采用事件委托机制,不会在 li 标签上直接添加,而是在 ul 父元素上添加。
优点:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制。
# 29 事件循环
事务队列中,在每一次事件循环中,宏任务只会提取一个执行,而微任务会一直提取,直到微任务队列为空为止。
也就是说如果某个微任务任务被推入到执行中,那么当主线程任务执行完成后,会循环调用该队列任务中的下一个任务来执行,直到该任务队列到最后一个任务为止。而事件循环每次只会入栈一个宏任务,主线程执行完成该任务后又会检查微任务队列并完成里面的所有任务后再执行宏任务队列的任务。
宏任务:setTimeOut、setInterval、setImmediate、IO、UI 渲染、主 JS、requestAnimationFrame 等。
微任务:process.nextTick、promise.then(),Object.observe()等
# 30 图片懒加载和预加载
懒加载:迟缓加载甚至不加载。(减少服务器的压力)
- 实现方法:图片地址不放在 src,而是放在其它属性,页面加载后,根据 scrollTop 判断图片是否在用户视野内,如果在,则将 data-original 属性中的值放在 src。在滚动事件中重复判断图片是否进入视野。
预加载:提前加载图片,当用户需要查看时直接从本地缓存中渲染。(会增大服务器的压力)
CSS 实现:background:url()
JS 实现:
const img = new Image(); img.src = 'xxx';
# 31 new 操作符
new 操作符新建了一个空对象,这个对象原型指向构造函数的 prototype,执行构造函数后返回这个对象
实现一个 new 的方法:
function Animal(){...} //var a = new Animal(); function myNew(){ let obj = {} let Constructor = [].shifit.apply(arguments); //绑定原型 obj.__proto__ = Constructor.prototype; //调用构造函数 let res = Constructor.apply(obj, arguments); return typeof res === 'object' ? res : obj; }
# 32 bind、apply、call 的区别
- apply 和 call 用来改变函数的 this 指向,它们两个函数的第一个参数都是一样的,表示要改变指向的那个对象,第二个参数,apply 中是数组,而 call 是 arg1,arg2…的形式。
- bind 改变 this 作用域会返回一个新的函数,这个函数不会立即执行。
# 33 节流和防抖
防抖:持续拖动滚动条,只要不停止触发,就永远不会有输出。短时间内触发的事件,在某个时间期限内,函数只执行一次。
function debounce(func, wait){ var timeout; return function(){ clearTimeout(timeout); timeout = setTimeout(func,wait); } }
节流:持续拖动滚动条,每间隔一段时间,就会输出反馈。相当于技能冷却,执行之后,函数会失效一段时间,冷却之后,又会恢复,设置一个状态位,判断是否处于工作状态。(在防抖基础上,到达指定事件必须输出)
function throttle(func, wait, mustRun){ var timeout, start = new Data(); return function(){ var context = this, args = arguments; var cur = new Data(); clearTimeout(timeout); if (cur - start >= mustRun){ func.apply(context, args); start = cur; } else { timeout = setTimeout(func, wait); } } }
# 34 深拷贝
简单深拷贝:JSON 序列化和反序列化
function deepCopy(obj){ let __obj = JSON.stringify(obj); return JSON.parse(_obj); }
递归方法:
function deepCopy(obj){ let res; if (typeof obj === 'Object'){ if (Array.isArray(obj)){ res = [] for (let i in obj){ res.push(deepCopy(obj[i])) } } else if (obj == null){ res = null; } else if (obj.constructor === 'RegExp'){ res = obj; } else { res = {} for (let i in obj){ res[i] = deepCopy(obj[i]) } } } else { res = obj; } return res; }
# 35 对象属性改变监听-Proxy
示例
var user = new Proxy({}, { set:function(target,key,value,receiver){ } })
# 36 变量提升和暂时性死区
变量提升:var 定义变量,变量可以在声明前使用,值为 undefined;let 不会出现这个情况。
暂时性死区 TDZ:只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等待变量声明的那一行代码出现,才可以获取和使用该变量。
只要块级作用域内存在 let 和 const 命令,它所声明的变量就会绑定这个区域,不再受外部影响。
# 37 箭头函数
基本语法
let func = value=>value; //aka let func = function(value){ return value; };
与普通函数的区别
- 箭头函数没有 this,如果普通函数包含箭头函数,那么 this 访问的就是最近一层普通函数的 this
- 箭头函数是匿名函数,不能作为构造函数,不能使用 new
- 箭头函数没有自己的 arguments 参数,虽然有 name 属性但是是空字符串,用…扩展运算符。
- 箭头函数通过 call()或 apply()方法调用一个函数时,只传入了一个参数,对 this 并没有影响。
- 箭头函数没有原型属性 prototype
# 38 原型链
原型:prototype,是一个对象,作用是共享属性和方法
原型链:原型与原型层层连接的过程即为原型链
假设 B 继承了 A,b 是 B 的实例,那么就有以下关系:
(1)
b.__proto__ = B.prototype
(2)B.prototype.constructor = B,A.prototype.constructor = A
(3)
B.__proto__ = A
(4)
B.prototype.__proto__ = A.prototype
# 39 ES6 新特性
- let(解决了变量提升)、 const 常量,块级作用域(暂时性死区)。
- 模板字符串:“xxx${}”
- 箭头函数
- 对象,数组解构赋值
- for in 和 for of
- class 类
- extend 类继承
# 40 垂直居中的方法
- margin:auto,left、right、top、bottom 全设为 0
- display:flex,align-items:center,justify-content:center;
# 41 前端性能优化
- 降低请求量:合并资源、减少 HTTP 请求数、minify/gzip 压缩,webP,懒加载
- 加快请求速度:预解析 DNS、减少域名数、并行加载、CDN 分发
- 缓存:HTTP 协议缓存请求、离线缓存 manifest、离线数据缓存 localStorage
- 渲染:JS/CSS 优化,加载顺序,服务端渲染,pipeline
# 42 get 和 post 的区别
- get 参数通过 url 传递,post 放在 request body 中
- get 请求在 url 中传递的参数有长度限制,post 没有
- get 参数暴露在 url,不安全。
- get 请求只能进行 url 编码,post 支持多种编码方式
- get 请求浏览器会主动缓存。
- get 请求参数会被完整保留在浏览历史记录。
- get 用来获取资源,post 用来增加或更新资源。
# 43 web worker
在 HTML 页面中,如果在执行脚本时,页面的状态是不可响应的,直到脚本执行完成后,页面才变成可响应。web worker 是运行在后台的 js,独立于其他脚本,不会影响页面你的性能。并且通过 postMessage 将结果回传到主线程。这样在进行复杂操作的时候,就不会阻塞主线程了。
如何创建 web worker:
检测浏览器对于 web worker 的支持性
创建 web worker 文件(js,回传函数等)
创建 web worker 对象
# 44 浮动清除
- overflow:hidden/auto
- 给浮动的元素的容器添加浮动
# 45 CSS 选择器
ID 选择器、Class 选择器、标签选择器、伪元素选择器、伪类选择器
优先级:
- 引入了同类的选择器:排在后面的样式属性优先
- 引入了不同的选择器:id>class>标签