1.用过es6哪些方法;最新更新的方法是哪些?
1.1.声明方式
let、const
1.2.扩展运算符(...)
作用:
合并数组;
复制数组;
将数组转为用逗号隔开的参数序列;
将数组转为函数的参数;
将字符串转换成数组
1.3.Set数据结构
数组去重Array.from(new Set(array))
1.4.箭头函数
1.5.async、await函数
1.6.数组的find()方法
1.7.includes()
1.8.flat()将多维数组转为一维数组,可传入Infinity关键字作为参数,可将任意维数的数组转为一维
1.9.sort()排序
2.讲讲promise
作用:解决回调地狱的问题
方法:catch()、then()、finally()
3.http和https的区别
3.1.传输信息安全性不同:HTTP协议是超文本传输协议,信息是明文传输的;HTTPS是具有安全性的ssl加密传输协议,为浏览器和服务器之间的通信加密,确保数据传输的安全;
3.2.连接方式不同:HTTP协议是无状态的连接;HTTPS协议是通过ssl和HTTP协议构建的可进行加密传输、身份认证的网络协议。
3.3.端口号不同:前者使用80;后者使用443
3.4.证书申请方式不同:前者免费;后者需要到ca申请证书,一般需要付费申请
3.5.前者的特点是支持客户/服务器模式;灵活(允许传送任意类型的数据对象);简单快速(客户向服务器请求服务时,只需传送请求方法和路径;由于HTTP协议及简单,使得HTTP协议的服务器程序规模小,因而通信速度快);无连接(限制每次连接只处理一个请求);无状态(无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。)
4.请求方式有哪几种
4.2.Get:向特定资源发出请求(请求指定页面信息,并返回尸体主题)
4.3.Post:向指定资源提交数据进行处理请求(提交表单、上传文件),有可能导致新的资源的建立或原有资源的修改
4.4.Put 向指定资源位置上上传其最新内容(从客户端向服务器传送的数据取代指定文档的内容)
4.5.Head 与服务器索与get请求一致的相应,响应体不会返回,获取包含在消息头中额度原信息(与get请求类似,返回的相应中没有具体内容,用于获取报头)
4.6.Delect 请求服务器删除request-URL所标示的资源(请求服务器删除页面)
4.7.Trace 回显服务器收到的请求,用于测试和诊断
4.8.Connect HTTP/1.1协议中能够将连接改为管道方式的代理服务器
5.get和post的本质区别
5.1.get是从服务器上获取;post向服务器传送数据
5.2.数据传送方式不同;提交数据的安全性不同;get传递的请求数据按照key-value的方式放在URL后面,在网址上可以直接看到;post方法会把请求的参数放在请求头部和请求体中以&分割各个字段,请求行不包含参数,URL中不会额外福大参数;所以安全性比post方法的差。(post的放在request body中)
请求体:空格下面的请求数据字段就是请求正文
6.盒子模型
6.1.标准盒模型:宽度=content
6.2.怪异盒模型:宽度=content + 左右边框+左右填充
7.用过css4的哪些属性
7.1
8.项目中遇到哪些难点
8.1.浮点数乘以整数时数值不对的情况
解决方案:function exactNumber(num, multiple){
if(String(num).includes('.')){
const numArr = String(num).split ('.')
return Number(numArr[0]) * multiple + Number(numArr[1] )*multiple / Math.pow(10, numArr[1] .length)
}
}
9.负责项目中的哪个模块
10.文件上传用的什么方法
10.1.用插件:element ui
10.2.formdata
11.跨域怎么解决?
导致跨域问题的原因是不同源,同源是指域名、端口、协议三者均相同
11.1.jsonp:是一种跨域的数据交互协议,通过script标签进行请求,然后后台就会根据相应的json、handleResponse等参数来生成相应的json数据,最后这个json数据就会被放在当前js文件中执行(script标签请求回来的资源与当前域是相同的域名)
原理:首先在客户端注册一个callback,然后把callback的名字传给服务器;服务器先生成json数据,然后以js语法的方式生成一个函数,函数名字就是传递上来的参数jsonp,最后将json数据直接以入参的方式,放置到函数中,这样就生成了一段js语法的文档,返回给客户端;客户端浏览器再解析script标签,并执行返回的js文档,此时数据作为参数,传入到了客户端预先定义好的callback函数里,动态执行回调函数
11.2.cors:使用自定义的HTTP头部让浏览器和服务器进行沟通,从而决定请求或响应是否成功。
var xdr = new XDomainRequest(); xdr.onload = function(){ console.log(xdr.responseText); } xdr.open('get', 'http://www.baidu.com'); ...... xdr.send(null);
11.3.webSocket:是一种浏览器的api,目标是在一个单独的持久连接上提供全双工、双向同信。原理是创建一个webSocket之后,会有一个HTTP请求发送到浏览器以发起连接,取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为webSocket协议。
11.4.postMessge
12.接口返回的状态码分别是什么意思?1开头的状态码表示什么意思?以此类推。。。
参考连接https://www.jianshu.com/p/f11b99b069d0
13.cookie、sessionStorage、localStorage、session、webStorage的区别
13.1.前三者都是存储在浏览器中的,且同源;cookie数据始终都在HTTP请求中携带,可以在浏览器和服务器之间来回传递,而且cookie可以限制在某个路径进行访问;sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存;
13.2.存储数据大小不同:cookie不能超过4k;后两者5M或更大
13.3.数据有效期不同:cookie数据在设置的过期时间之前会一直存在;localStorage数据不删除就会一直存在;sessionStorage关闭页面之后就会失效
13.4.作用域不同:cookie和localStorage在所有同源窗口中数据是共享的;sessionStorage在不同的浏览器中,即使是同一个页面都不能共享数据。
14.响应式布局和自适应布局
14.1.区别
响应式布局是实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。
自适应则需要开发多套界面来适应终端
后者通过检测视口分辨率来判断当前访问的设备是:pc端、平板、还是手机,从而请求服务层,返回不同的页面;响应式布局通过检测视口分辨率,针对不同客户端在客户端做代码处理来展示不同的布局和内容
后者需要开发多套界面;前者只需要一套
后者对页面做的屏幕适配是在一定范围:比如pc端一般要大于1024像素,手机端要小于768像素。而响应式是一套页面全部适应
自适应布局如果屏幕太小会发生内容过于拥挤。而响应式布局就是为了解决这个问题而衍生的概念,它可以自动识别屏幕宽度并作出相应的网页设计
14.2.实现
14.2.1.响应式布局的父元素宽高尽量由子元素撑起来,父元素的宽高设置成百分比;
字体使用相对大小‘rem’(相对于根元素的字体大小)或者‘em’(相对于父元素的字体大小的单位,如果当前行内文本的字体大小未被设置,则相对于浏览器的默认字体尺寸);
图片的大小也要用百分比设置,宽度可设置为auto,最大宽度设置为100%,这样可以防止图片超过原始尺寸而导致模糊的问题
14.2.2.自适应布局是利用媒体查询设置相应屏幕宽度大小的情况下,采用不同的布局
@media only screen and (max- 500px) { body { background-color: lightblue; } }
15.怎么获取登录信息
session.getAttribute(String key)
16.实现弹性盒布局的方式有哪几种
17.描述一下事件流的过程
捕获目标然后冒泡;window-document-html-body-。。。-目标元素-。。。body-html-document-window
18.dom的事件有哪些?
20.做过哪些浏览器的兼容?
20.1.各个浏览器的标签的margin和padding有差异,所以可以将对应使用的标签的margin和padding设置为0
20.2.IE6双边距的问题:块级元素设置了浮动样式,同时设置margin,就会产生这类问题,解决方案,将元素设置为行内元素
20.3.标签设置高度低于10px时,在IE6和IE7中会超出自己设置的高度:该标签的行高的设置成比高度低的值或者设置overflow:hidden
20.4.图片之间有默认间距:将父元素的字体大小设置为0;
20.5.IE9以下的浏览器不能使用opacity:
20.6.边距重叠的问题:当相邻两个元素都设置边距时,元素统一使用最大值,舍弃最小值
20.9.获取目标属性不同:IE浏览器用event.srcElement,其他浏览器用event.target
document.getElementById('element').innerText = "my text";
} else{
document.getElementById('element').textContent = "my text";
}
21.如何判断一个变量是否为数值类型
typeof(num) === 'number' && num !== Infinity && !isNaN(num)
22.typeof可以得到哪些值
22.1.number
typeof(数值类型)、typeof(Infinity)、typeof(NaN)
22.2.object
typeof(对象/数组)、typeof(null)、typeof(window)
22.3.undefined
typeof(未声明的变量、已声明未赋值的变量)
22.4.function
typeof(Array)、typeof(Date)、typeof(Function)
22.5.string
typeof(字符串)
22.6.boolean
typeof(true)、typeof(false)
22.页面保护措施有哪些?
22.1.预防跨脚本攻击(xss),
1.将重要的信息存放在session中或者将重要的cookies标记为HTTP ONLY,让js无法调用,只能通过http调用;
2.只允许客户输入我们期望的数据(如输入框只能输入数字);
3.对数据进行加密处理;
4.过滤或者移除特殊的HTML标签和js代码等。
22.2.cxss(跨站请求伪造):跨脚本攻击利用站点内的信任用户;跨站请求伪造是通过伪装来自受信任用户,在受信任的网站进行请求,盗取信息。其实就是攻击者盗用了受害者的身份,以受害者的名义向网站发送恶意请求;我们可以通过以下方式进行防护:
1.在表单里增加Hash值,以认证这确实是用户发送的请求,然后在服务器端进行Hash值验证。
2.验证码:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串。
3.修改,增加重要信息,比如密码,个人信息的操作,尽量使用post。避免使用get把信息暴露在url上面。
22.3.反爬虫
1.元素定位覆盖式
2.伪元素
23.报文由哪几部分构成?各部分都有什么作用?
HTTP报文由报文首部和报文主体构成,中间由一个空行分隔。 报文首部是客户端或服务器端需处理的请求或响应的内容及属性, 可以传递额外的重要信息。报文首部包括请求行和请求头部,报文主体主要包含应被发送的数据。通常,不一定有报文主体
24.window.onload和ready的区别
window.onload 需要加载完所有文档(包括图像和外部资源)才会执行;只能执行一次,如有多次,第一次的执行会被覆盖掉
$(document).ready{}是html下载完成并dom树生成之后,代码就会执行。一般情况一个页面响应加载的顺序是,域名解析-加载html-加载js和css-加载图片等其他信息。那么Dom Ready应该在“加载js和css”和“加载图片等其他信息”之间,就可以操作Dom了。可以执行多次,第n次都不会被上一次覆盖
25.讲一下双向绑定的原理
利用Object.defineProperty()重新定义了对象获取属性值和设置属性值的操作来实现的。它接收三个参数,第一个是要操作的对象,第二个是定义或修改的对象的属性名,第三个是属性描述符。重点是最后的属性描述符。属性描述符是一个对象,主要有两种形式:数据描述符和存取描述符。这两种对象只能选择一种使用,不能混合两种描述符的属性同事使用。
eg:let obj = {}
var name
Object.defineProperty(obj, 'data', {
ge() {
return name
},
set(newName) {
val = newName
}
})
26.js的数据类型有哪些
26.1基本数据类型:Number、String、Boolean、null、undefined、Symbol
26.2.引用数据类型:Object
27.Symbol的作用
防止属性名冲突,保证每个属性名都是唯一的,是一种类似于字符串的类型
通过Symbol函数生成Smybol值
28.异步编程的方法有哪几种?
28.1.回调函数
28.2.事件监听
28.3.发布/订阅
28.4.promise对象
28.5.es6的Generator函数
29.异步和同步的区别
异步是一个任务不是连续完成的,它可以先执行一段,然后转去执行其他的任务,等做好了准备,再执行任务剩下的部分。
同步是连续的执行任务,所以中途不能插入其他任务
30.vue.nextTick()的原理
在下次dom更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的dom。
31.对自己有没有制定一些目标或者计划
找一家稳定的公司,根据公司需求,努力提升自己,成为对公司有用的员工。
32.如何实现三列布局?
32.1.左右元素浮动,中间的元素的宽度用calc计算
32.2.绝对定位,中间的元素不给宽度
32.3.flex布局,左右设置flex-basis,中间设置flex-grow(其中flex-basis相当于宽度的作用,但同时设置时,flex-basis的优先级高于width;)
33.设置了flex属性之后,元素的哪些属性会失效
浮动,vertical-align、clear
34.rem的原理(单位计算公式)
根据根节点的字体大小来设置其他元素的大小,实现不同设备的自适应是通过重新设置根节点的字体大小来实现的。
根节点的新的字体大小 = 窗口文档显示区的宽度/设计图的宽度 * 根节点(html)的旧的字体大小
35.自己写过哪些组件
如何实现样式的继承和复用?
创建公用样式的文件,不同元素使用同样的样式时,可以设置统一的类名进行样式的复用;像一些文本属性和列表属性子元素都可以继承,所以一般都会创建一个基本样式文件初始化一些标签的样式
36.哪些样式会被继承
字体和列表的样式
37.使用过sass的哪些功能
变量(声明:$name: pink;使用:color: $name)
样式嵌套
计算
注释(标准的css注释/*...*/;单行注释 //。。。;重要是注释,可用于声明版权/*!..。、/)
继承(允许一个选择器继承另一个选择器的样式@extend 选择器)
参考链接http://www.ruanyifeng.com/blog/2012/06/sass.html
38.event loop(事件轮询)
JavaScript是单线程的编程语言,所以就会产生一个问题,就是必须要等前一个程序执行完毕才能执行下一个程序。所以程序就分为了两类,同步任务和异步任务,异步任务中包含宏任务和微任务,script标签和setTimeOut,setInterval都是宏任务;promise和nextTick是微任务
它执行过程就是执行宏任务结束到微任务结束的过程
39.防抖和节流
防抖就是触发事件后让事件在规定时间内只触发一次
/*
func:要执行的函数;wait:等待执行的毫秒时间;immediate是否立即执行
*/
function debounce(func, wait, immediate){
let timeout
return function(){
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
if(immediate) {
var callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(() => {
func.apply(context, args)
}, wait)
}
}
}
节流是连续触发事件但在规定时间内只执行一次
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait ,type) {
if(type===1){
let previous = 0;
}else if(type===2){
let timeout;
}
return function() {
let context = this;
let args = arguments;
if(type===1){
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}
40.水平垂直居中
定位
flex布局
41.promise、generator、async,await的区别
promise是通过resolve和reject方法触发事件,然后用then和catch方法获取成功或失败返回的数据并可执行相应的处理代码;generator函数是通过将函数分步骤阻塞,只有主动调用next()才会进行下一步;async就是generator的语法糖,在await的部分等待返回,返回后自动执行下一步;比promise好的是不需要链式调用,直接用同步的写法就可以了。
42.前端性能优化
减少http请求、延迟加载组件、预加载组件
使用精灵图
使用cdn:将内容分发到多个处于不同地域的服务器上可提高加载速度
使用link标签代替@import加载样式
把js和css文件当做外部文件引入使用,因为这两种文件在浏览器能产生缓存
43.BFC(块级格式化上下文)的理解
形成:float的值不为none;overflow的值不为visible ;position的值不为static、relative;display的值为table-cell、table-caption、inline-block
意思就是该元素的内部元素的定位和布局跟外部元素互不影响
应用场景:高度塌陷;阻止外边距叠加 ;元素左右浮动,遮挡住中间的元素时,给中间的元素添加overflow:hidden的样式即可
44.从浏览器输入url直到页面渲染,期间有哪些步骤
1.dns解析url的过程
2.浏览器发送请求与服务器交互的过程
3.浏览器对接收到的html页面渲染的过程
参考连接:https://www.cnblogs.com/qing-5/p/11126524.html
45.call、apply、bind的区别
call和apply的区别是传参方式不同,apply的第二个参数必须是数组类型的;call和bind的区别是bind的函数不是立即执行的,call是立即执行的
46.组件通信
参考连接:https://segmentfault.com/a/1190000019208626
47.斜对角输出二维数组的所有数据
function slash(arr) {
let str = ''
if(arr.length === 0) return
let col = arr[0].length;
let row = arr.length;
//k表示输出多少行,斜对角输出会有col*2-1行
for( let k = 0 ; k < col * 2 -1 ; k++ ) {
for( let j = 0 ; j < col ; j++ ) {
let i = k - j;
if(isValidIndex(i, row) && isValidIndex(j, col)) {
str = str + arr[j][i]
}
}
}
return str
}
//反向斜角
function isValidIndex(i, n) {
return i >= 0 && i < n;
}
slash([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
48.将字符串中与数组中一致的元素去除
function getText(str, arr) {
// 将数组重新排序,按字符长度从大到小排序
let newArr = arr.sort((a, b) => b.length - a.length)
let newStr = null
newArr.forEach(item => {
str = str.replace(item, '')
let items = str.split(item)
newStr = items.join('')
})
return newStr
}
49.将数组中的元素进行排列组合,输出满足相加等于0的组合
50.this的指向问题
一般函数中的this指向全局对象window;对象的方法调用,this指向调用该方法的对象;在严格模式下,this是undefined;构造函数中的this指向创建的实例;
可用bind(),call(),apply()改变this指向,其中bind不会立即执行,call和apply会立即执行,bind和call的参数传递一样,apply的第二个参数必须是数组类型
51。什么场景下需要用到vuex
中大型的单页应用,因为vuex可以为组件提供共享数据和通信渠道
52。js的继承
创建对象的几种方式都可以实现js的继承
父类
function Person(name){
this.name = name
}
原型链继承:通过用new一个父类的方式赋值给子类的prototype(让新实例的原型等于父类的实例)
function Per () {
this.name = 'kiki'
}
Per.prototype = new Person()
var pre1 = new Per()
instanceof可以判断一个元素是否在另一个元素的原型链上,返回boolean值
缺点:不会继承父类实例的属性;新实例无法向父类的构造函数传参
构造函数:用call或者apply把值作为参数传递给父类
缺点是只继承了父类实例上的属性,但是没有继承父类原型上的属性;无法实现构造函数的复用;每个新实例都有父类的构造函数的副本,显得臃肿
原型链和构造函数组合
缺点:调用了两次父类构造函数耗内存
寄生组合继承
寄生:在函数内返回对象然后调用
组合:函数原型等于另一个实例;
将父类的原型作为参数赋值给构造函数的原型,然后在组合构造函数中改变父类this的指向,之后将子类实例赋值给组合构造函数的原型,然后修复子类的实例
//寄生
function content(obj){
function F(){}
F.prototype = obj
return new F()
}
var con = content(Person.prototype)
//组合
function Sub(){
Person.call(this)
}
Sub.prototype = con
con.constructor = Sub
var sub1 = new Sub()
53.url的解析过程
1.。浏览器发起dns查询请求;
2.建立tcp连接
3.连接成功之后浏览器会接收到服务器返回来的数据进行解析;这个浏览器解析的过程就是先加载html文档,然后在加载的过程中遇到外部的css文件和图片资源时都会另外发起一个请求来获取css文件,但是不会影响到html文档的加载,如果遇到js文件的话,html文档会挂起渲染线程,它需要等js文件加载并解析完后才会恢复渲染线程
54.react,angular和vue的区别
参考连接https://www.cnblogs.com/zhuchenglin/p/9485879.html
react和vue都有组件化的概念,都是基于js的框架,angular是基于typeScript的框架,没有组件化概念。angular和react比较适合大型的技术生态系统。
react的组件渲染需要通过jsx,可以将HTML嵌入到js中实现视图页面,vue则推荐用模板进行组件渲染(也支持jsx);vue是双向绑定,react是单向数据流,angular是mvc;angular有模块化和灵活性
55.MVC和mvvm,mvp的区别
mvc的所有通信都是单向的,mvp各部分之间的通信都是双向的;view和model不发生通信关系,通过presenter传递;mvvm和mvp相似;但是view和viewModal是双向绑定的,当其中一方发生变化时,都会自动反应在另一方上
56.state,getters,mutation,action
state用来存放状态数据,在组件中可用mapState获取多个状态;state派生出来的状态可用getters实现,组件中可用mapGetters进行映射;mutation是对修改state状态的提交,可用commit进行提交,mutation只能处理同步函数;所以action可以提交mutation,可以处理异步函数;通过dispatch对action进行分发
57.
function quickSort(arr, left, right) {
/*
* len为数组的长度;
* left为需要数组中参与排序的起始点;right为数组中参与排序的终止点;
* left如果有传数字那么就为left,没有传参则为0;
* right如果有传参那么就为right,没有传参则为len-1;
* 有传参可能会部分排序可能不会排序,没传参默认排序整个数组;
* partitionIndex为分组界限;
*/
var len = arr.length,
partitionIndex,
left = typeof left !== 'number' ? 0 : left,
right = typeof right !== 'number' ? len - 1 : right;
// 如果需要排序的起始索引小于终止索引则执行排序;递归的终止条件;
if (left < right) {
// partition的返回值作为partitionIndex来分隔数组;
// 索引partitionIndex左边的元素均小于arr[partitionIndex];
// 右边的元素均大于arr[partitionIndex];
partitionIndex = partition(arr, left, right);
// 数组中小于arr[partitionIndex]的部分(索引left到partitionIndex-1)再次使用quickSort排序;
quickSort(arr, left, partitionIndex - 1);
// 数组中大于arr[partitionIndex]的部分(索引partitionIndex+1到right)再次使用quickSort排序;
quickSort(arr, partitionIndex + 1, right);
}
// 递归执行直到不满足left<right;返回本身;
return arr;
}
function partition(arr, left, right) {
/*
* 这部分是具体实现排序的部分;
* 将left赋值给pivot,作为参照物,因为left在最左边,只需要从左到右比较一遍即可判断整个数组;
* index索引是arr中待交换位置;
*/
var pivot = left,
index = pivot + 1;
// for循环从参照物arr[pivot]下一个元素arr[pivot+1]开始一直比较到子数组结束arr[right];
for (var i = index; i <= right; i++) {
// 循环中如果有任何小于参照物的,就将他交换到index的位置,然后index向右移动到下一个位置;
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
/*
* 因为每次都是交换完后index移动到下一个位置,所以在循环结束时,index仍为待交换的位置;
* 此时索引pivot+1到index-1的元素都小于参照物arr[pivot];
*/
// 交换pivot和index-1索引的值之后index-1索引左边全都是小于arr[index-1]的元素;
swap(arr, pivot, index - 1);
// 返回index-1作为拆分子数组的分界线;
return index - 1;
}
/*
* 普通的交换,将a[i]和a[j]的数值交换;
*/
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
58,小程序中遇到的难点
59。后端返回数据过大时,前端怎么优化
60.vue使用的是什么模式,内部处理机制是什么
61.vue2。0和3.0的区别
62.小程序的通信方式
63.weakpack中如何配置打包方式
配置入口文件通过resolve或者配置loader时,通过test,exclude,include,缩小文件搜索范围;
配置plugin插件,减少基础模块的编译;使用haapypack开启多进程loader转换;使用parallelUglifyPlugin开启多进程压缩js文件
优化开发
使用weakpack监听开启自动刷新
64.重绘和回流
重绘是指render tree的元素更新属性时,只发生外观,风格的改变,不影响元素的布局时,就称为重绘
回流是指当render tree因为元素的规模尺寸,布局,隐藏等发生改变而需要重构的,就称为回流
回流一定引起重绘,重绘不一定引起回流(因为回流时,浏览器会使渲染树受影响的部分失效,然后重新构造这部分的render tree,直到回流结束之后又浏览器会重新布局,绘制受影响的部分到屏幕中),添加或删除dom,设置边框,宽度,高度,边距,填充会发生回流;改变背景颜色会发生重绘
解决方案
避免操作dom,可以通过操作display属性值为none的节点来实现操作都没节点,因为这种节点不呈现在页面,不会改变页面布局
避免设置多层样式
将需要多次回流的元素的属性position的属性值设为absolute或者fixed,因为脱离的文档标准流的元素发生改变不会影响到其他元素