一、移动web部分1、前端页面有哪三层构成，分别是什么？作用是什么？1、结构层：由 HTML 标记语言负责创建，仅负责语义的表达。解决了页面“内容是什么”的问题。 2、表示层：由CSS负责创建，解决了页面“如何显示内容”的问题。 3、行为层：由脚本（js）负责。解决了页面上“内容应该如何对事件作出反应”的问题2、主流的浏览器分别是什么内核？Trident内核：（国产的绝大部分浏览器）IE，360，搜狗 Gecko内核：Firefox，NetScape6及以上 Presto内核：Opera7及以上 Webkit内核：（国产大部分双核浏览器其中一核）Safari（苹果），Chrome3、如何居中一个浮动元素?父元素和子元素同时左浮动，然后父元素相对左移动50%，再然后子元素相对右移动50%，或者子元素相对左移动-50%也就可以了。 Test Float Element Center 4、行内元素有哪些？块级元素有哪些？空元素（void）有哪些？1、行内元素：a，b，span，img，input，strong，label，button，select，textarea，em 2、块级元素：div，ul（无序列表），ol，li，dl（自定义列表），dt（自定义列表项），dd（自定义列表项的定义），p，h1-h6，blockquote（块引用） 3、空元素（void）：即没有内容的HTML元素。br（换行），hr（水平分割线），meta，link，input，img5、BFC（Block Formatting Context，块级格式化上下文）1、是什么：决定了元素如何对其内容进行定位，以及与其他元素的关系和相互作用。简言之，就是一个特殊的块，内部的元素和外部的元素不会相互影响。BFC内的盒子会在垂直方向上一个接一个地放置，垂直方向上也会发生外边距重叠。 2、应用场景：自适应布局（BFC不与float box重叠）、清除浮动（计算BFC的高度时，内部的浮动元素也被计算在内）、防止外边距重叠 3、如何触发BFC：float属性（不为none）、overflow属性（不为visible）、position属性（absolute，fixed）、display属性（inline-block，table-cell，table-caption，flex，inline-flex）6、CSS选择器的优先级!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符 > 继承 7、初始化CSS样式的意义1、为什么要初始化CSS样式：因为浏览器的兼容问题，不同浏览器对有些标签的默认值是不同的，如果没有对CSS初始化往往会出现浏览器之间的页面显示差异。8、HTML5新增了哪些属性1. 语义化标签: header nav section article aside footer 2. 多媒体标签: video audio 3. input类型: number search email tel date file time url 4. 本地离线存储 localStorage 长期存储数据,改变浏览器数据不会丢失 sessionStorage 浏览器关闭数据会丢失 5. 自定义属性 data-* 6. 画布 Canvas 7. webscoket 双向通信协议9、CSS3新增了哪些属性1. 圆角 border-radius 2. 盒子模型 box-sizing 3. 阴影 box-shadow 盒子阴影 text-shadow 文字阴影 4. 过渡 transition 5. 2D转换transform translate(平移) scale(缩放) skew(斜切) rotate(旋转) transform-origin 控制转换中心点 6. 3D转换 perspective(透视距) transform-style(3D控件效果) 7. 渐变 linear-gradient radial-gradient 8. 弹性布局 flex 9. 媒体查询 @media screen and () {...} 10. 边框图片 border-image 11. 自定义动画 @keyframes animation 12. 颜色 新增RGBA HSLA模式 13. 背景 background-size background-origin background-clip10、对HTML语义化的理解1、用正确的标签做正确的事情 2、HTML语义化让页面的内容结构化，结构更清晰，便于对浏览器、搜索引擎解析 3、即使在没有样式CSS情况下也以一种文档格式显示，并且是易于阅读的 4、搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重，利于SEO 5、使阅读源代码的人更容易将网站分块，便于阅读维护理解11、CSS的盒子模型1、有两种， IE 盒子模型、W3C 盒子模型； 2、盒模型： 内容(content)、填充(padding)、边界(margin)、 边框(border)； 3、区 别： IE的content部分把 border 和 padding计算了进去;11.1、css写一个三角形答: div { width: 0; height: 0; border: 20px solid transparent; border-width: 40px 20px 0 0; border-right-color: #f99; }12、如何居中div1、 水平居中：给div设置一个宽度，然后添加margin:0 auto属性 div{ width:200px; margin:0 auto;} 2、让绝对定位的div居中 div { position: absolute; width: 300px; height: 300px; margin: auto; top: 0; left: 0; bottom: 0; right: 0; background-color: pink; } 3、水平垂直居中一 确定容器的宽高 宽500 高 300 的层 设置层的外边距 div { position: relative; /* 相对定位或绝对定位均可 */ width:500px; height:300px; top: 50%; left: 50%; margin: -150px 0 0 -250px; /* 外边距为自身宽高的一半 */ background-color: pink; /* 方便看效果 */ } 4、水平垂直居中二 未知容器的宽高，利用 `transform` 属性 div { position: absolute; /* 相对定位或绝对定位均可 */ width:500px; height:300px; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: pink; /* 方便看效果 */ } 5、水平垂直居中三 利用 flex 布局 实际使用时应考虑兼容性 .container { display: flex; align-items: center; /* 垂直居中 */ justify-content: center; /* 水平居中 */ } .container div { width: 100px; height: 100px; background-color: pink; /* 方便看效果 */ } 13、不定宽高的div水平垂直居中答: 1、父元素添加 position: relative div{ position:absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } 2、div { display: flex; justify-content:center; //子元素水平居中 align-items:center; //子元素垂直居中 } 3、#box { width: 100px; height: 100px; position: relative; } #content { width: 50px; height: 50px; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; }14、px/em/rem有什么区别1、px 是固定的像素，一旦设置了就无法因为适应页面大小而改变 2、em 和rem相对于px更具有灵活性，他们是相对长度单位，意思是长度不是定死了的，更适用于响应式布局 3、em 相对自身font-size，没有则相对于父元素，rem相对于根元素的font-size15、rem布局的原理1、rem 是css的相对单位，rem缩放是相对根元素字体大小. 2、rem 布局的本质是等比缩放，一般是基于宽度。 3、rem 会配合媒体查询（或js动态获取屏幕宽度）来一起使用，来实现屏幕的适配。16、盒子塌陷的原因？解决方式原因: 1. 浮动导致的塌陷,浮动会脱落标准流 2. 嵌套的两个盒子,子盒子设置margin-top会导致父盒子一下下移 解决方法:第一种情况 1 清除浮动; 2 给父盒子加高度; 3 给父元素添加overflow:hidden 第二种情况 1 给父元素加上边框; 2 给父元素添加overflow:hidden17、如何设置比12px更小的字体答: p { font-size:12px; -webkit-transform:scale(0.8); }18、flex常用的容器属性答: 1. flex-direction: 设置容器中的主轴方向 2. flex-wrap: 项目在主轴方向上是否换行显示 3. justify-content: 设置容器中的项目在主轴上的对齐方式 4. align-items: 单行项目在侧轴上的排列方式 5. align-content: 多行项目侧轴上的对齐方式 6. flex-flow: 是flex-direction和flex-wrap的合写, 默认值为row nowrap二、JS基础部分1、什么是重绘和重排答: 重排: 当DOM元素影响了元素的几何属性（例如宽和高），浏览器需要重新计算元素的几何属性，同样其它元素的几何属性也会和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效，并重新构造渲染树。这个过程称为“重排”。 重绘: 完成重排后，浏览器会重新绘制受影响的部分到屏幕上中，该过程称为“重绘”。 当我们改变DOM的大小，增加删除都会导致重排，当给DOM元素改变颜色的时候，会导致重绘，重排一定会重绘，重绘不会重排。重排会影响性能，所以我们尽快能的减少重排的操作2、js的数据类型有哪些答: 简单数据类型: number string boolean undefined null 复杂数据类型: object function array3、js的运行机制是什么答：js是单线程执行的，页面加载时，会自上而下执行主线程上的同步任务，当主线程代码执行完毕时，才开始执行在任务队列中的异步任务。具体如下 1.所有同步任务都在主线程上执行，形成一个执行栈。 2.主线程之外，还存在一个"任务队列(eventloop队列或者消息队列)"。只要异步任务有了运行结果，就在"任务队列"之中放置一个事件。 3.一旦"执行栈"中的所有同步任务执行完毕，系统就会读取"任务队列"，看看里面有哪些事件。哪些对应的异步任务，于是结束等待状态，进入执行栈，开始执行。 4.主线程不断重复上面的第三步。3.1、异步函数有哪些JavaScript 中常见的异步函数有：定时器，事件和 ajax 等4、typeof返回的数据类型答: number string boolean undefined object function 特殊情况： typeof null -->object typeof array -->object typeof typeof 任何类型 -->string5、返回false的情况有哪些答: 0 "" null false NaN undefined 不成立的表达式6、对this的理解``` this是个关键字,它的指向和函数的调用方式有关 1. 函数调用模式, this指向window 2. 构造函数调用模式, this指向新创建的实例对象 3. 方法调用模式, this指向调用方法的对象 4. 上下文调用模式, call和apply方法中, this指向方法内的第一个参数 bind方法中, bind创建的新函数的this绑定为bind方法中新的函数 5. 在事件处理函数中,this指向触发事件的当前元素 6. 定时器中,this指向window 7. 箭头函数中没有this指向问题,它的this和外层作用域的this保持一致 8. 匿名函数中的this总是指向window ​````7、null和undefined的区别答：null 表示空值 没有获取到。typeof null 返回"object" undefined 表示未定义，声明没有值。typeof undefined 返回"undefined"8、let、const、var的区别1、var声明变量存在提升（提升当前作用域最顶端），let和const是不存在变量提升的情况 2、var没有块级作用，let和const存在块级作用域 3、var允许重复声明，let和const在同一作用域不允许重复声明 4、var和let声明变量可以修改，const是常量不能改变9、==和===的区别答：== 表示是相等，只比较内容 === 表示是全等，不仅比较内容，也比较类型10、伪数组和真数组的区别伪数组： 1、拥有length属性 2、不具有数组的方法 3、伪数组是一个Object，真数组是Array 4、伪数组的长度不可变，真数组的长度是可变的11、哪些情况会得到伪数组1、参数 arguments， arguments 是一个类数组对象，里面保存着调用函数时传入的实参 2、DOM 对象列表（比如通过 document.getElementsByTags 得到的列表）、childNodes也是伪数组 3、jQuery 对象（比如 $("div")）12、本地存储localStorage、sessionStorage和cookie的区别答: 共同点: 都可以用来存储数据。 区别: 1. 请求不同: cookie 数据始终在同源的http请求中携带（即使不需要），即cookie在浏览器和服务器间来回传递。 sessionStorage 和 localStorage不会自动把数据发给服务器，仅在本地保存。 2. 存储大小限制也不同: cookie 数据不能超过4k，同时因为每次http请求都会携带cookie，所以cookie只适合保存很小的数据，如会话标识。 sessionStorage 和 localStorage虽然也有存储大小的限制，但比cookie大得多，sessionStorage和localStorage约5M 。 3. 数据有效期不同: sessionStorage：仅在当前浏览器窗口关闭前有效，自然也就不可能持久保持； localStorage：始终有效，窗口或浏览器关闭也一直保存，因此用作持久数据； cookie只在设置的cookie过期时间之前一直有效，即使窗口或浏览器关闭。 三、JS高级部分1、值类型和引用类型的区别1、值类型 1）基本类型数据是值类型 2）保存与复制的是值本身 3）使用typeof检测数据的类型 2、引用类型 1）保存与复制的是指向对象的一个指针 2）使用instanceof检测数据类型 3）使用 new() 方法构造出的对象是引用型 2、什么是深拷贝什么是浅拷贝答: 浅拷贝: 拷贝对象的一层属性,如果对象里面还有对象,拷贝的是地址, 两者之间修改会有影响,适用于对象里面属性的值是简单数据类型的. 深拷贝: 拷贝对象的多层属性,如果对象里面还有对象,会继续拷贝,使用递归去实现.3、如何实现深拷贝和浅拷贝浅拷贝: var obj = { class: 'UI', age: 20, love: 'eat' } function getObj(obj) { var newObj = {} for (var k in obj) { newObj[k] = obj[k] } return newObj } var obj2 = getObj(obj) console.log(obj2)深拷贝: var obj = { class: '前端', age: 26, love: { friuts : 'apple', meat: 'beef' } } function getObj(obj) { var newObj = {} for (var k in obj) { /* if (typeof obj[k] == 'object') { newObj[k] = getObj(obj[k]) } else { newObj[k] = obj[k] } */ newObj[k] = typeof obj[k] == 'object' ? getObj(obj[k]) : obj[k] } return newObj } var obj2 = getObj(obj) console.log(obj2)4、什么是原型和原型链答: 原型: 函数都有prototype属性,这个属性的值是个对象,称之为原型 原型链: 对象都有__proto__属性,这个属性指向它的原型对象,原型对象也是对象,也有__proto__属性,指向原型对象的原型对象,这样一层一层形成的链式结构称为原型链.5、call、apply和bind的区别答: 14、call、apply和bind的区别 ​``` 答: 1. call和apply方法都可以调用函数,方法内的第一个参数可以修改this的指向 2. call方法可以有多个参数,除了第一个参数,其他参数作为实参传递给函数 apply方法最多有2个参数,第二个参数是个数组或伪数组,数组里面的每一项作为实参传递给函数 3. bind方法不能调用函数,它会创建一个副本函数,并且绑定新函数的this指向bind返回的新的函数 ​```6、怎么理解面向对象答：1、面向对象是一种软件开发的思想和面向过程是相对应的，就是把程序看作一个对象，将属性和方法封装其中，以提高代码的灵活性、复用性、可扩展性。 2、面向对象有三大特性：封装、继承、多态。 封装：把相关的信息（无论数据或方法）存储在对象中的能力 继承：由另一个类（或多个类）得来类的属性和方法的能力 多态：编写能以多种方法运行的函数或方法的能力 3、基本思想是使用对象，类，继承，封装等基本概念来进行程序设计 易维护 易扩展 开发工作的重用性、继承性高，降低重复工作量。 缩短了开发周期 4、js中对象是一个无序的数据集合或者也可以说是属性和方法的集合，可以动态的添加属性可方法。 5、js是基于对象，但是也使用了嵌入了面向对象的思想，可以实现继承和封装，这样也可以提供代码的灵活性和复用性。7、数组如何进行降维（扁平化）1、利用Array.some方法判断数组中是否还存在数组，es6展开运算符连接数组 let arr = [1,2,[3,4]] while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } 2、使用数组的concat方法 let arr = [1,2,[3,4]] let result = [] result = Array.prototype.concat.apply([], arr) 3、 使用数组的concat方法和扩展运算符 var arr = [1,2,[3,4]] var result = [] result = [].concat(...arr) 4、es6中的flat函数也可以实现数组的扁平化 let arr = [1,2,['a','b',['中','文',[1,2,3,[11,21,31]]]],3]; let result = arr.flat( Infinity ) 注意：flat方法的infinity属性，可以实现多层数组的降维8、对闭包的理解？并能举出闭包的例子答: 闭包 函数和声明该函数的词法环境的组合(两个嵌套关系的函数,内部函数可以访问外部函数定义的变量) 闭包的优点：1、形成私有空间，避免全局变量的污染 2、持久化内存，保存数据 闭包的缺点：1、持久化内存，导致内存泄露 解决：1、尽快避免函数的嵌套，以及变量的引用 2、执行完的变量，可以赋值null，让垃圾回收机制，进行回收释放内存（当不在引用的变量，垃圾回收机制就会回收）例: 点击li获取当前下标 111 222 333 444 555 var lis = document.querySelectorAll('li') for (var i = 0; i < lis.length; i++) { (function (j) { lis[j].onclick = function () { console.log(j) } })(i) }9、es6-es10新增常用方法答: es6: 1、let、const 2、解构赋值 let { a, b } = { a: 1, b: 2 } 3、箭头函数 ()=>{} 4、字符串模板 `` 5、扩展运算符 ...arr 6、数组方法：map、filter、some等等 7、类：class关键字 8、promise 主要用于异步计算 9、函数参数默认值 fn(a = 1) {} 10、对象属性简写 let a = 1; let obj = {a} 11、模块化：import--引入、exprot default--导出 es7: 1、includes()方法，用来判断一个数组是否包含一个指定的值，根据情况，如果包含则返回true，否则返回false。 es8: 1、async/await es9： 1、Promise.finally() 允许你指定最终的逻辑 es10: 1、数组Array的flat()和flatmap() flat:方法最基本的作用就是数组降维 var arr1 = [1, 2, [3, 4]]; arr1.flat(); // [1, 2, 3, 4] var arr3 = [1, 2, [3, 4, [5, 6]]]; arr3.flat(2); // [1, 2, 3, 4, 5, 6] //使用 Infinity 作为深度，展开任意深度的嵌套数组 arr3.flat(Infinity); // [1, 2, 3, 4, 5, 6] flatmap:方法首先使用映射函数映射(遍历)每个元素，然后将结果压缩成一个新数组四、Ajax部分1、原生注册事件的方式？区别是什么答: 注册方式 1. on + 事件名称 2. addEventListener 区别: 1. 使用on注册事件,同一个元素只能注册一个同类型事件,否则会覆盖。 2. addEventListener可以注册同一事件多次,不会被覆盖。2、http和https的区别答: 1.https协议需要到CA申请证书，一般免费证书较少，因而需要一定费用。 2.http是超文本传输协议，信息是明文传输，https则是具有安全性的ssl/tls加密传输协议。 3.http和https使用的是完全不同的连接方式，用的端口也不一样，前者是80，后者是443。 4.http的连接很简单，是无状态的；HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议，比http协议安全。3、get 和post的区别答: get 1. 在url后面拼接参数,只能以文本的形式传递数据 2. 传递的数据量小,4KB左右 3. 安全性低, 会将数据显示在地址栏 4. 速度快,通常用于安全性要求不高的请求 5. 会缓存数据 post 1. 安全性比较高 2. 传递数据量大,请求对数据长度没有要求 3. 请求不会被缓存,也不会保留在浏览器历史记录里4、原生 ajax 请求的步骤答：1.创建异步对象 var xhr = new HTMLHttpRequest() 2.设置请求行 xhr.open() 3.设置请求头 xhr.setRequestHeader() get请求没有请求头 4.设置请求体 xhr.send 5.设置监听事件 addEventListener('load',function)5、项目中常遇到的状态码有哪些答: 200 请求成功, 2开头的异步表示请求成功 304 请求被允许,但请求内容没有改变, 3开头的一般请求完成 400 请求格式错误, 4开头的一般表示请求错误 404 请求的资源(网页)不存在, 500 内部服务器错误, 5开头的一般都是指服务器错误6、什么是同源策略？怎么解决跨域问题答: 同源策略: 同源策略是浏览器的一种安全策略, 所谓同源是指域名、协议、端口完全相同，不同源则跨域。 解决跨域的方法: 1. 通过jsonp跨域 2. 跨域资源共享（CORS Access-Control-Allow-Origin: http://api.bob.com） 3. nginx代理跨域7、jsonp的原理？以及优答: 原理: 利用script标签的src属性具有天然可跨域的特性，由服务端返回一个预先定义好的Javascript函数的调用，并且将服务器数据以该函数参数的形式响应给浏览器. 优点: 完美解决在测试或者开发中获取不同域下的数据,用户传递一个callback参数给服务端，然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据，这样客户端就可以随意定制自己的函数来自动处理返回数据了。 缺点：Jsonp只支持get请求而不支持post 请求,也即是说如果想传给后台一个json 格式的数据,此时问题就来了, 浏览器会报一个http状态码41错误,告诉你请求格式不正确.8、在地址栏输入网址，到数据返回的过程是什么？答: 1. 输入url地址后，首先进行DNS解析，将相应的域名解析为IP地址。 2. 根据IP地址去寻找相应的服务器。 3. 与服务器进行TCP的三次握手，建立连接。 4. 客户端发送请求，找到相应的资源库。 5. 客户端拿到数据，进行相应的渲染。9、你对WebSocket了解哪些答: WebSocket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信，能更好的节省服务器资源和带宽并达到实时通讯，它建立在TCP之上，同HTTP一样通过TCP来传输数据，但是它和HTTP最大不同是： 1. WebSocket是一种双向通信协议，在建立连接后，WebSocket服务器和Browser/Client Agent都能主动的向对方发送或接收数据，就像Socket一样； 2. WebSocket需要类似TCP的客户端和服务器端通过握手连接连接成功后才能相互通信。10、怎么理解三次握手字段 含义 URG 紧急指针是否有效。为1，表示某一位需要被优先处理 ACK 确认号是否有效，一般置为1。 PSH 提示接收端应用程序立即从TCP缓冲区把数据读走。 RST 对方要求重新建立连接，复位。 SYN 请求建立连接，并在其序列号的字段进行序列号的初始值设定。建立连接，设置为1 FIN 希望断开连接。 1、三次握手 第一次握手：建立连接时，客户端发送syn包到服务器，等待服务器确认。 第二次握手：服务器收到syn包，必须确认客户的SYN，同时自己也发送一个SYN包（syn=y）到客户端 第三次握手：客户端收到服务器的SYN+ACK包，向服务器发送确认包ACK，此包发送完毕，客户端和服务器进入（TCP连接成功）状态，完成三次握手 （通俗：主机1告诉主机2，我可以向你请求数据吗。主机2告诉主机1，可以请求数据。主机1告诉主机2，那我来请求数据了，请求完成，实现三次握手）11、怎么理解四次挥手1、四次挥手 第一次分手：主机1（可以使客户端，也可以是服务器端）向主机2发送一个FIN报文段；此时，主机1进入FIN_WAIT_1状态；这表示主机1没有数据要发送给主机2了。 第二次分手：主机2收到了主机1发送的FIN报文段，向主机1回一个ACK报文段，主机1进入FIN_WAIT_2状态；主机2告诉主机1，我“同意”你的关闭请求。 第三次分手：主机2向主机1发送FIN报文段，请求关闭连接，同时主机2进入LAST_ACK状态。 第四次分手：主机1收到主机2发送的FIN报文段，向主机2发送ACK报文段，然后主机1进入TIME_WAIT状态；主机2收到主机1的ACK报文段以后，就关闭连接；此时，主机1等待2MSL后依然没有收到回复，则证明Server端已正常关闭，那好，主机1也可以关闭连接了。 （通俗：主机1告诉主机2，我没有数据要发送了，希望断开连接。主机2接到请求后说，同意断开。主机2告诉主机1可以关闭连接了。主机1接到可以关闭的指令后，关闭连接，四次挥手完成）12、json 与 对象和数组之间的转化json 本质上就是一个字符串, 数组或者对象的字符串表示法 序列化 对象和数组 ===> json JSON.stringify(对象或者数组) 反序列化 json ===> 对象或者数组 JSON.parse(json)13、怎么理解函数的防抖和节流答: 1、定义： 防抖: 就是指触发事件后在n秒内函数只能执行一次，如果在n秒内又触发了事件，则会重新计算函数执行时间。 例如：设定1000毫秒执行，当你触发事件了，他会1000毫秒后执行，但是在还剩500毫秒的时候你又触发了事件，那就会重新开始1000毫秒之后再执行 节流: 就是指连续触发事件但是在设定的一段时间内中只执行一次函数。 例如：设定1000毫秒执行，那你在1000毫秒触发在多次，也只在1000毫秒后执行一次 2、防抖和节流的实现： 14、axios的特点有哪些1、Axios 是一个基于 promise 的 HTTP 库，支持promise所有的API 2、它可以拦截请求和响应 3、它可以转换请求数据和响应数据，并对响应回来的内容自动转换成 JSON类型的数据五、大事件和node阶段1、对this的理解答: this是个关键字,它的指向和函数的调用方式有关 1. 函数调用模式, this指向window 2. 构造函数调用模式, this指向新创建的实例对象 3. 方法调用模式, this指向调用方法的对象 4. 上下文调用模式, call和apply方法中, this指向方法内的第一个参数 bind方法中, bind创建的新函数的this绑定为bind方法中新的函数 5. 在事件处理函数中,this指向触发事件的当前元素 6. 定时器中,this指向window 7. 箭头函数中没有this指向问题,它的this和外层作用域的this保持一致 8. 匿名函数中的this总是指向window2、new操作符做了什么答: 1. 创建一个新对象 2. 函数内部的this指向这个对象 3. 执行函数体 4. 自动返回这个函数 创建新的空对象 2.将构造函数中的this指向创建的新的空对象 3.执行构造函数中的代码 4.把创建的新对象给返回出去3、git如何管理一个项目1、git管理项目流程 答: 1、git init初始化git仓库（新项目才有这一步） 2、git clone将远程仓库的项目资料下载下来 3、git checkout -b dev (dev 为本地分支名） 4、git add .将工作区文件存在暂存区 4、git commit -m ""从暂存区存到仓储区 5、git checkout master切到master分支 6、git merge dev 合并分支,合并后要将分支删除 7、使用git push将其上传到远程仓库 8、第二上班，先pull一下，更新最新代码4、git如何解决合并冲突git解决合并冲突 答：冲突的原因：代码提交的时候，在当前行有新的代码要加入，就会出现冲突。例如：20行已经有代码了，但是合并的的代码20行也是有代码，这样就会出现冲突。 解决办法：如果是双方的代码是不同的业务，那就保留双方双方更改（vscode有提示）。如果是重复的业务逻辑，那就选择采用当前更改（vscode有提示）。 5、什么是promise，特点是什么 首先，它是一个对象，也就是说与其他JavaScript对象的用法，没有什么两样；它使得异步操作具备同步操作的效果，使得程序具备正常的同步运行的流程，回调函数不必再一层层嵌套。 简单说，它的思想是，每一个异步任务立刻返回一个Promise对象，由于是立刻返回，所以可以采用同步操作的流程。这个Promises对象有一个then方法，允许指定回调函数，在异步任务完成后调用。 特点： 1、Promise对象只有三种状态。 异步操作“未完成”（pending） 异步操作“已完成”（resolved，又称fulfilled） 异步操作“失败”（rejected） 异步操作成功，Promise对象传回一个值，状态变为resolved。 异步操作失败，Promise对象抛出一个错误，状态变为rejected。 2、promise的回调是同步的，then是异步的 3、可以链式调用6、promise的方法有哪些，能说明其作用原型上的方法： 1、Promise.prototype.then() 1）作用是为 Promise 实例添加状态改变时的回调函数。接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用，第二个回调函数是Promise对象的状态变为rejected时调用。其中，第二个函数是可选的，不一定要提供。 2）返回的是另一个Promise对象，后面还可以接着调用then方法。 2、Promise.prototype.catch() 1）用于指定发生错误时的回调函数。 2）返回的也是一个 Promise 对象，因此还可以接着调用then方法 3、Promise.prototype.finally() 1）finally方法用于指定不管 Promise 对象最后状态如何，都会执行的回调函数。 2）finally方法的回调函数不接受任何参数，这意味着没有办法知道，前面的 Promise 状态到底是fulfilled还是rejected。 自身API: 1、Promise.resolve() 1）不带参数传递 — 返回一个新的状态为resolve的promise对象 2）参数是一个 Promise 实例— 返回 当前的promise实例 2、Promise.reject() 1)返回的是一个值 2）返回的值会传递到下一个then的resolve方法参数中 3、Promise.all() 1）并行执行异步操作的能力 2）所有异步操作执行完后才执行回调 4、Promise.race() 1）那个结果返回来的快就是，那个结果，不管结果是成功还是失败7、async和await是干什么的1、async 用于申明一个 function 是异步的，而 await 用于等待一个异步方法执行完成。 2、await 只能出现在 async 函数中。 3、async 函数返回的是一个 Promise 对象，后面可以用then方法。8、怎么理解事件循环机制(Event Loop) 1、JavaScript 是一门单线程语言.单线程可能会出现阻塞的情况，所js分了同步任务和异步任务。 2、同步和异步任务分别进入不同的执行环境，同步的进入主线程，即主执行栈，异步的进入 Event Queue（事件队列） 。主线程内的任务执行完毕为空，会去 Event Queue 读取对应的任务，推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。9、宏任务和微任务1、先执行同步和立即执行任务，比如说console.log()、new Promise()2、再依次执行微任务，比如说then函数3、当微任务执行完成后开始执行宏任务，比如说定时器、事件回调等六、vue阶段面试题1、怎么理解mvvm这种设计模式 Model–View–ViewModel （MVVM） 是一个软件架构设计模式，是一种简化用户界面的事件驱动编程方式。 MVVM M Model 模型 指的是数据层 V View 视图 指的是用户页面 VM ViewModel 视图模型 视图模型是MVVM模式的核心，它是连接view和model的桥梁，MVVM实现了view和model的自动同步，当model的属性改变时，我们不用自己手动操作DOM元素，来改变view的显示，反之亦然，我们称之为数据的双向绑定。2、v-if和v-show的区别，使用场景区别v-if和v-show看起来似乎差不多，当条件不成立时，其所对应的标签元素都不可见，但是这两个选项是有区别的: 1、v-if在条件切换时，会对标签进行适当的创建和销毁，而v-show则仅在初始化时加载一次，因此v-if的开销相对来说会比v-show大。 2、v-if是惰性的，只有当条件为真时才会真正渲染标签；如果初始条件不为真，则v-if不会去渲染标签。v-show则无论初始条件是否成立，都会渲染标签，它仅仅做的只是简单的CSS（display）切换。 3、v-if适用于不需要频繁切换元素显示和隐藏的情况 v-show适用于需要频繁切换元素的显示和隐藏的场景。3、事件修饰符和按键修饰符有哪些事件修饰符： .prevent 阻止事件默认行为 .stop 阻止事件冒泡 .capture 设置事件捕获机制 .self 只有点击元素自身才能触发事件 .once 事件只触发一次 按键修饰符： .tab .enter .esc .space .delete(捕获"删除"和"空格"键) .up .down .left .right4、v-model修饰符有哪些.trim 去除首尾空格 .lazy 只在输入框失去焦点或按回车键时更新内容，不是实时更新 .number 将数据转换成number类型(原本是字符串类型)5、v-for中为什么要加key作用： 1.key的作用主要是为了高效的更新虚拟DOM，提高渲染性能。 2.key属性可以避免数据混乱的情况出现。 原理： 1.vue实现了一套虚拟DOM，使我们可以不直接操作DOM元素只操作数据，就可以重新渲染页面，而隐藏在背后的原理是高效的Diff算法 2.当页面数据发生变化时，Diff算法只会比较同一层级的节点； 3.如果节点类型不同，直接干掉前面的节点，再创建并插入新的节点，不会再比较这个节点后面的子节点； 如果节点类型相同，则会重新设置该节点属性，从而实现节点更新 4.使用key给每个节点做一个唯一标识，Diff算法就可以正确失败此节点，"就地更新"找到正确的位置插入新的节点。6、v-for和v-if的优先级 v-for优先级高于v-if 如果同时出现v-for和v-if，无论判断条件是否成立，都会执行一遍v-for循环，这样浪费性能，所以要尽可能的避免两者一起使用。7、组件中的data为什么是函数,new Vue 实例里，data 可以直接是一个对象1、组件是用来复用的，组件中的data写成一个函数,数据以函数返回值形式定义,函数有独立的作用域，这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。 2、而单纯的写成对象形式,由于对象是引用类型，就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。 3、因为new vue里面的代码是不存在复用的情况，所以可以写成对象形式8、computed和watch的区别是什么计算属性computed： 1、支持缓存，只有依赖数据发生改变，才会重新进行计算 2、不支持异步，当computed内有异步操作时无效，无法监听数据的变化 3、如果computed需要对数据修改，需要写get和set两个方法，当数据变化时，调用set方法。 4、computed擅长处理的场景：一个数据受多个数据影响，例如购物车计算总价 侦听属性watch： 1、不支持缓存，数据变，直接会触发相应的操作； 2、watch支持异步；监听的函数接收两个参数，第一个参数是最新的值；第二个参数是输入之前的值； 3、immediate：组件加载立即触发回调函数执行 4、deep:true的意思就是深入监听，任何修改obj里面任何一个属性都会触发这个监听器里的 handler方法来处理逻辑 5、watch擅长处理的场景：一个数据影响多个数据，例如搜索框9、组件化和模块化的区别1、组件相当于库，把一些能在项目里或者不同类型项目中可复用的代码进行工具性的封装。 2、模块相应于业务逻辑模块，把同一类型项目里的功能逻辑进行需求性的封装。10、怎么理解vue中的虚拟DOM原理： 用 JavaScript 对象模拟真实 DOM 树，对真实 DOM 进行抽象；diff 算法 — 比较两棵虚拟 DOM 树的差异；pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。 好处： 1、性能优化 2、无需手动操作DOM 3、可以跨平台，服务端渲染等11、怎么理解vue的生命周期 vue的生命周期：vue实例从创建到销毁的全过程，这个过程可以分为3个阶段 第一阶段：初始化阶段 创建vue实例,准备数据,准备模板,渲染视图 第二阶段：数据更新阶段 当数据变化时，会进行新旧DOM的对比，对比出差异的部分，进行差异化更新。 第三阶段：实例销毁阶段 当vm.$destroy()被调用，vue实例就会被销毁，释放相关资源，此时再更新数据，视图不会再变化。12、vue 钩子函数有哪些，有哪些使用的场景1、各阶段包含钩子： beforeCreate 在data数据注入到vm实例之前，此时vm身上没有数据 created 在data数据注入到vm实例之前，此时vm身上有数据 beforeMount 生成的结构替换视图之前，此时DOM还没更新 mounted 生成的结构替换视图之前，此时DOM已经更新完成 beforeUpdate 数据变化了，dom更新之前 updated 数据变化了，dom更新之后 activated 被keep-alive缓存的组件激活时调用 deactivated 被keep-alive缓存的组件停用时调用 beforeDestroy 实例销毁，是否资源之前 destroyed 实例销毁，是否资源之后这些钩子函数会在vue的生命周期的不同阶段，自动被vue调用 2、常用的钩子函数使用场景： beforeCreate 做loading的一些渲染 created 结束loading， 发送数据的请求，拿数据 mounted 可以对dom进行操作 updated 监视数据的更新 beforeDestroy 销毁非vue资源，防止内存泄漏，例如清除定时器 activated 当我们运用了组件缓存时，如果想每次切换都发送一次请求的话，需要把请求函数写在activated中，而写在created或mounted中其只会在首次加载该组件的时候起作用。13、Vue 的父组件和子组件生命周期钩子函数执行顺序1、Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下4部分： 1）加载渲染过程 :父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted 2）子组件更新过程 :父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated 3）父组件更新过程 :父 beforeUpdate -> 父 updated 4）销毁过程 :父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed 14、vue组件传值的方式1、父传子 通过props传递 父组件： <child :list = 'list' /> 子组件: props['list'],接收数据,接受之后使用和data中定义数据使用方式一样 2、子传父 :在父组件中给子组件绑定一个自定义的事件，子组件通过$emit()触发该事件并传值。 父组件： <child @receive = 'getData' /> getData(value){value就是接收的值} 子组件: this.$emit('receive',value) 3、兄弟组件传值通过中央通信 let bus = new Vue() A组件：methods :{ sendData(){ bus.$emit('getData',value) } 发送 B组件：created(){ bus.$on(‘getData’,(value)=>{value就是接收的数据}) } 进行数据接收15、$nextTick是什么？原理是什么背景： 1、简单来说，Vue 在修改数据后，视图不会立刻更新，而是等同一事件循环中的所有数据变化完成之后，再统一进行视图更新。 定义： 2、在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法，获取更新后的 DOM。nextTick()，是将回调函数延迟在下一次dom更新数据后调用，简单的理解是：当数据更新了，在dom中渲染后，自动执行该函数。 原理 3、vue用异步队列的方式来控制DOM更新和nextTick回调先后执行。 简单来说，nextTick是做了promise加上setTimeout的封装,利用事件换行机制，来确保当nextTick出现时，都是在我们所有操作DOM更新之后的场景 4.1 点击获取元素宽度 4.2 使用swiper插件通过 ajax 请求图片后的滑动问题 4.3 点击按钮显示原本以 v-show = false 隐藏起来的输入框，并获取焦点16、vue是如何获取DOM1、先给标签设置一个ref值，再通过this.$refs.domName获取，这个操作要在mounted阶段进行。 2、例如： mounted(){ const dom = this.$refs.test }17、v-on可以监听多个方法吗可以例如： 18、谈谈你对 keep-alive 的了解1、keep-alive 是 Vue 内置的一个组件，可以使被包含的组件保留状态，避免重新渲染 2、一般结合路由和动态组件一起使用，用于缓存组件 3、对应两个钩子函数 activated 和 deactivated ，当组件被激活时，触发钩子函数 activated，当组件被移除时，触发钩子函数 deactivated 4、 include 字符串，数组或正则表达式。只有名称匹配的组件会被缓存。 exclude 字符串，数组或正则表达式。任何名称匹配的组件都不会缓存。 max 数字。最多可以缓存多少组件实例。 其中 exclude 的优先级比 include 高； 例如： include: <keep-alive include="a"> <component></component> </keep-alive> exclude: <keep-alive exclude="a"> <component></component> </keep-alive>19、谈谈你对slot的了解1、什么是插槽 (1) 插槽（Slot）是Vue提出来的一个概念，正如名字一样，插槽用于决定将所携带的内容，插入到指定的某个位置，从而使模板分块，具有模块化的特质和更大的重用性。 (2) 插槽显不显示、怎样显示是由父组件来控制的，而插槽在哪里显示就由子组件来进行控制 2、插槽使用 (1) 默认插槽 在子组件中写入slot，slot所在的位置就是父组件要显示的内容 (2) 具名插槽 在子组件中定义了三个slot标签，其中有两个分别添加了name属性header和footer 在父组件中使用template并写入对应的slot名字来指定该内容在子组件中现实的位置 (3) 作用域插槽 在子组件的slot标签上绑定需要的值<slot :data="user"></slot> 在父组件上使用slot-scope=“user”来接收子组件传过来的值 20、vue中动态组件如何使用1、在某个中使用 is 特性来切换不同的组件： <component :is="TabComponent"></component> TabComponent:已注册组件的名字21、v-model的原理是什么1、v-model主要提供了两个功能，view层输入值影响data的属性值，属性值发生改变会更新层的数值变化. 2、v-model指令的实现： 3.1 v-bind:绑定响应式数据 3.2 触发input事件并传递数据 (核心和重点)3、其底层原理就是(双向数据绑定原理)： 3.1 一方面modal层通过defineProperty来劫持每个属性，一旦监听到变化通过相关的页面元素更新。 3.2 另一方面通过编译模板文件，为控件的v-model绑定input事件，从而页面输入能实时更新相关data属性值。22、vue响应式的原理1、原理： Vue 的响应式原理是核心是通过 ES5 的 Object.defindeProperty 进行数据劫持，然后利用 get 和 set 方法进行获取和设置，data 中声明的属性都被添加到了get和set中，当读取 data 中的数据时自动调用 get 方法，当修改 data 中的数据时，自动调用 set 方法，检测到数据的变化，会通知观察者 Wacher，观察者 Wacher自动触发重新render 当前组件（子组件不会重新渲染）,生成新的虚拟 DOM 树，Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别，并记录下来，最后，加载操作，将所有记录的不同点，局部修改到真实 DOM 树上。 2、底层代码实现： let data = { name: "lis", age: 20, sex: "男" } vue2.0实现： 使用Object.defineProperty进行数据劫持 for(let key in data){ let temp = data[key] Object.defineProperty(data, data[key], { get(){ return temp}, set(value){temp = value} } )} vue3.0实现 : 使用Proxy 进行数据的代理 let newData = new Proxy(data, {get(target, key){ return target[key]} set(target, key, value) { target[key] = value } })23、vue2.0和vue3.0响应式的区别1、Object.defineProperty (1) 用于监听对象的数据变化 (2) 无法监听数组变化(下标，长度) (3) 只能劫持对象的自身属性，动态添加的劫持不到 2、Proxy (1) proxy返回的是一个新对象， 可以通过操作返回的新的对象达到目的 (2)可以监听到数组变化，也可以监听到动态添加的数据24、router和route的区别1.$router对象 $router对象是全局路由的实例，是router构造方法的实例 $router对象上的方法有：push()、go()、replace() 2、$route对象 $route对象表示当前的路由信息，包含了当前 URL 解析得到的信息。包含当前的路径， $route对象上的属性有：path、params、query、hash等等 25、路由传参的方式和区别1、方式：params 和 query 2、区别： （1）params用的是name，传递的参数在地址栏不会显示，类似于post （2）query用的是path,传递的参数会在地址栏显示出来，类似于get 3、举例说明： （1）params 传参 传： this.$router.push({ name: 'particulars', params: { id: id } }) 接：this.$route.params.id （2）.query传参 传：this.$router.push({ path: '/particulars', query: { id: id } }) 接：this.$route.query.id26、Vue模版编译原理知道吗，能简单说一下吗1、简单说，Vue的编译过程就是将template转化为render函数的过程。 2、首先解析模版，生成AST语法树(一种用JavaScript对象的形式来描述整个模板)。 使用大量的正则表达式对模板进行解析，遇到标签、文本的时候都会执行对应的钩子进行相关处理。 3、Vue的数据是响应式的，但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化，对应的DOM也不会变化。那么优化过程就是深度遍历AST树，按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的比对，对运行时的模板起到很大的优化作用。4、编译的最后一步是将优化后的AST树转换为可执行的代码。27、SSR了解吗1、SSR也就是服务端渲染，也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成，然后再把html直接返回给客户端。 2、SSR有着更好的SEO、并且首屏加载速度更快等优点。 3.缺点：比如我们的开发条件会受到限制，服务器端渲染只支持beforeCreate和created两个钩子 当我们需要一些外部扩展库时需要特殊处理，服务端渲染应用程序也需要处于Node.js的运行环境。还有就是服务器的压力比较大。28、你都做过哪些Vue的性能优化1、v-if和v-for不能连用 2、页面采用keep-alive缓存组件 3、合理使用v-if和v-show 4、key保证唯一 5、使用路由懒加载、异步组件、组件封装 6、防抖、节流 7、第三方模块按需导入 8、图片懒加载 9、精灵图的使用 10、代码压缩29、Vue-router 路由有哪些模式一般有两种模式： 1、hash 模式：后面的 hash 值的变化，浏览器既不会向服务器发出请求，浏览器也不会刷新， 每次 hash 值的变化会触发 hashchange 事件。 2、history 模式：利用了 HTML5 中新增的 pushState() 和 replaceState() 方法。 这两个方法应用于浏览器的历史记录栈，在当前已有的 back、forward、go 的基础之上，它们提供了对历史记录进行修改的功能。只是当它们执行修改时，虽然改变了当前的 URL，但浏览器不会立即向后端发送请求。30、Vuex 是什么？有哪几种属性？1、Vuex 是专为Vue设计的状态管理工具，采用集中式储存管理 Vue 中所有组件的状态。 2、属性 （1）state属性：基本数据 （2）getters属性：从 state 中派生出的数据 （3）mutation属性：更新 store 中数据的唯一途径，其接收一个以 state 为第一参数的回调函数 （4）action 属性：提交 mutation 以更改 state，其中可以包含异步操作，数据请求 （5）module 属性：用于将 store分割成不同的模块。31、axios封装请求拦截器和响应拦截器interceptors：【ɪntərˈsɛptərz】 1、项目中会在utils文件中，封装一个request.js文件 2、通过axios.create()配置baseURL，并得到一个request实例 3、通过request.interceptors.request.use来配置请求拦截 4、通过request.interceptors.response.use来配置响应拦截32、webpack在项目中的常见配置1、 配置兼容编译ES6转成ES5 用babel来编译， npm i babel-core babel-loader babel-preset-env babel-polyfill babel-plugin-transform-runtime --save-dev 2、配置跨域代理服务 用proxy进行代理，在devServer里面配置， proxy:{ '/api':{target:代理的地址} } 3、配置打包路径 publicPath:'/' 4、配置打包出去文件 outputDir: 'dist' 5、配置执行环境变量 启动的端口 const port = process.env.port || process.env.npm_config_port || 9528 33、vue怎么实现强制刷新组件第一.使用this.$forceUpdate强制重新渲染 刷新当前组件 第二.使用v-if指令 <comp v-if="update"></comp> 刷新comp组件 34、在使用计算属性的时,函数名和data数据源中的数据可以同名吗?不可以 在初始化vm的过程，因为不管是计算属性还是data还是props 都会被挂载在vm实例上，会把data覆盖了,因此 这三个都不能同名35、vue中data的属性可以和methods中的方法同名吗?不可以 vue源码中的 initData() 方法会取出 methods 中的方法进行判断，如果有重复的就会报错36、你知道style加scoped属性的用途和原理吗用途：防止全局同名CSS污染原理：在标签加上v-data-something属性，再在选择器时加上对应[v-data-something]，即CSS带属性选择器，以此完成类似作用域的选择方式. scoped会在元素上添加唯一的属性（data-v-x形式），css编译后也会加上属性选择器，从而达到限制作用域的目的。37、如何在子组件中访问父组件的实例Vue中子组件调用父组件的方法，这里有三种方法提供参考： 1：直接在子组件中通过this.$parent.event来调用父组件的方法 2：在子组件里用$emit向父组件触发一个事件，父组件监听这个事件 3：父组件把方法传入子组件中，在子组件里直接调用这个方法38、watch的属性用箭头函数定义结果会怎么样不应该使用箭头函数来定义 watch :例如： watch: { a: () => { // 这里不应该用箭头函数 console.log(this); this.sum = this.a + this.b; } })。 理由是箭头函数绑定了父级作用域的上下文，所以 this 将不会按照期望指向 Vue 实例，this.a 将是 undefined。注意：methods里面定义的方法也不要用箭头函数40、怎么解决vue打包后静态资源图片失效的问题在vue-cli 需要在根目录下建一个vue.config.js 在里面配置publicPath即可默认值为/，更改为./就好了41、怎么解决vue动态设置img的src不生效的问题因为动态添加src被当做静态资源处理了，没有进行编译，所以要加上require。 42、EventBus注册在全局上时，路由切换时会重复触发事件，如何解决呢原因：因为我们的事件是全局的，它并不会随着组件的销毁而自动注销，需要我们手动调用注销方法来注销。解决：我们可以在组件的 beforeDestroy ,或 destroy 生命周期中执行注销方法，手动注销事件43、你认为vue的核心是什么组件化双向数据绑定44、在.vue文件中style是必须的吗？那script是必须的吗在.vue 文件中，template是必须的，而script与style都不是必须的。都没有的话那就是一个静态网页45、说说vue的优缺点优点： 1.数据驱动 2.组件化 3.轻量级 4.SPA(单页面) 5.版本3.0的界面化管理工具比较好使 6.vue易入门 7.中文社区强大，入门简单，提升也有很多的参考资料。缺点： 1.不支持IE8及以下浏览器 2.吃内存（每个组件都会实例化一个Vue实例，实例的属性和方法很多） 3.定义在data里面的对象，实例化时，都会递归的遍历转成响应式数据，然而有的响应式数据我们并不会用到， 造成性能上的浪费七、react高频面试题1、什么是虚拟DOM？ 虚拟 DOM (VDOM)是真实 DOM 在内存中的表示。UI 的表示形式保存在内存中，并与实际的 DOM 同步。这是一个发生在渲染函数被调用和元素在屏幕上显示之间的步骤，整个过程被称为调和。2、虚拟DOM实现的原理？1.虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象 2.状态变更时，记录新树和旧树的差异 3.最后把差异更新到真正的dom中3、类组件和函数组件之间的区别是啥？ 类组件可以使用其他特性，如状态 state 和生命周期钩子。 当组件只是接收 props 渲染到页面时，就是无状态组件，就属于函数组件，也被称为哑组件或展示组件。 函数组件和类组件当然是有区别的，而且函数组件的性能比类组件的性能要高，因为类组件使用的时候要实例化，而函数组件直接执行函数取返回结果即可。如果都能满足需求的情况下，为了提高性能，尽量使用函数组件。4、React 中 refs 干嘛用的？ Refs 提供了一种访问在render方法中创建的 DOM 节点或者 React 元素的方法。 可以在组件添加一个 ref 属性来使用，该属性的值是一个回调函数，接收作为其第一个参数的底层 DOM 元素或组件的挂载实例。5、在 React 中如何处理事件？ 为了解决跨浏览器的兼容性问题，SyntheticEvent(事件e) 实例将被传递给你的事件处理函数，SyntheticEvent是 React 跨浏览器的浏览器原生事件包装器，它还拥有和浏览器原生事件相同的接口，包括 stopPropagation() 和 preventDefault()。6、state 和 props 区别是啥？ props和state是普通的 JS 对象。虽然它们都包含影响渲染输出的信息，但是它们在组件方面的功能是不同的。即 1.state 是组件自己管理数据，控制自己的状态，可变； 2.props 是外部传入的数据参数，不可变； 3.没有state的叫做无状态组件，有state的叫做有状态组件； 4.多用 props，少用 state，也就是多写无状态组件。7、如何创建 refs？Refs 是使用 React.createRef() 创建的，并通过 ref 属性附加到 React 元素。在构造组件时，通常将 Refs 分配给实例属性，以便可以在整个组件中引用它们。8、什么是高阶组件？高阶组件(HOC)是接受一个组件并返回一个新组件的函数。基本上，这是一个模式，是从 React 的组合特性中衍生出来的，称其为纯组件，因为它们可以接受任何动态提供的子组件，但不会修改或复制输入组件中的任何行为。9、在构造函数调用 super 并将 props 作为参数传入的作用是啥？在调用 super() 方法之前，子类构造函数无法使用this引用，ES6 子类也是如此。将 props 参数传递给 super() 调用的主要原因是在子构造函数中能够通过this.props来获取传入的 props。10、什么是控制组件？ 在 HTML 中，表单元素如 、 和 通常维护自己的状态，并根据用户输入进行更新。当用户提交表单时，来自上述元素的值将随表单一起发送。 而 React 的工作方式则不同。包含表单的组件将跟踪其状态中的输入值，并在每次回调函数(例如onChange)触发时重新渲染组件，因为状态被更新。以这种方式由 React 控制其值的输入表单元素称为受控组件。11、讲讲什么是 JSX ？jsx是JavaScript的一种语法扩展，它跟模板语言很接近，但是它充分具备JavaScript的能力 当 Facebook 第一次发布 React 时，他们还引入了一种新的 JS 方言 JSX， 将原始 HTML 模板嵌入到 JS 代码中。 JSX 代码本身不能被浏览器读取，必须使用Babel和webpack等工具将其转换为传统的JS。 JSX中的标签可以是单标签，也可以是双标签，但必须保证标签是闭合的。12、为什么不直接更新 state 呢 ?如果试图直接更新 state ，则不会重新渲染组件。 需要使用setState()方法来更新 state。它调度对组件state对象的更新。当state改变时，组件通过重新渲染来响应。13、React 组件生命周期有哪些不同阶段？在组件生命周期中有四个不同的阶段 1.Initialization：在这个阶段，组件准备设置初始化状态和默认属性。 2.Mounting：react 组件已经准备好挂载到浏览器 DOM 中。这个阶段包括componentWillMount和componentDidMount生命周期方法。 3.Updating：在这个阶段，组件以两种方式更新，发送新的 props 和 state 状态。此阶段包括shouldComponentUpdate、componentWillUpdate和componentDidUpdate生命周期方法。 4.Unmounting：在这个阶段，组件已经不再被需要了，它从浏览器 DOM 中卸载下来。这个阶段包含 componentWillUnmount 生命周期方法。除以上四个常用生命周期外，还有一个错误处理的阶段 5.Error Handling：在这个阶段，不论在渲染的过程中，还是在生命周期方法中或是在任何子组件的构造函数中发生错误，该组件都会被调用。这个阶段包含了 componentDidCatch 生命周期方法。14、React 的生命周期方法有哪些？1.componentWillMount:在渲染之前执行，用于根组件中的 App 级配置。 2.componentDidMount：在第一次渲染之后执行，可以在这里做AJAX请求，DOM 的操作或状态更新以及设置事件监听器。 3.componentWillReceiveProps：在初始化render的时候不会执行，它会在组件接受到新的状态(Props)时被触发，一般用于父组件状态更新时子组件的重新渲染 4.shouldComponentUpdate：确定是否更新组件。默认情况下，它返回true。如果确定在 state 或 props 更新后组件不需要在重新渲染，则可以返回false，这是一个提高性能的方法。 5.componentWillUpdate：在shouldComponentUpdate返回 true 确定要更新组件之前件之前执行。 6.componentDidUpdate：它主要用于更新DOM以响应props或state更改。 7.componentWillUnmount：它用于取消任何的网络请求，或删除与组件关联的所有事件监听器。15、使用 React Hooks 好处是啥？首先，Hooks 通常支持提取和重用跨多个组件通用的有状态逻辑，而无需承担高阶组件或渲染 props 的负担。Hooks 可以轻松地操作函数组件的状态，而不需要将它们转换为类组件。 Hooks 在类中不起作用，通过使用它们，咱们可以完全避免使用生命周期方法， 例如 componentDidMount、componentDidUpdate、componentWillUnmount。 相反，使用像useEffect这样的内置钩子。16、什么是 React Hooks？Hooks是 React 16.8 中的新添加内容。它们允许在不编写类的情况下使用state和其他 React 特性。使用 Hooks，可以从组件中提取有状态逻辑，这样就可以独立地测试和重用它。Hooks 允许咱们在不改变组件层次结构的情况下重用有状态逻辑，这样在许多组件之间或与社区共享 Hooks 变得很容易。17、React 中的 useState() 是什么？useState 是一个内置的 React Hook。useState(0) 返回一个元组，其中第一个参数count是计数器的当前状态，setCounter 提供更新计数器状态的方法。 可以在任何地方使用setCounter方法更新计数状态-在这种情况下，咱们在setCount函数内部使用它可以做更多的事情，使用 Hooks，能够使咱们的代码保持更多功能，还可以避免过多使用基于类的组件。18、React 中的StrictMode(严格模式)是什么？React 的StrictMode是一种辅助组件，可以帮助咱们编写更好的 react 组件，可以使用<StrictMode />包装一组组件，并且可以帮咱们以下检查： 1.验证内部组件是否遵循某些推荐做法，如果没有，会在控制台给出警告。 2.验证是否使用的已经废弃的方法，如果有，会在控制台给出警告。 3.通过识别潜在的风险预防一些副作用。19、为什么类方法需要绑定到类实例？在 JS 中，this 值会根据当前上下文变化。 在 React 类组件方法中，开发人员通常希望 this 引用组件的当前实例， 因此有必要将这些方法绑定到实例。20、受控组件和非受控组件区别是啥？受控组件是 React 控制中的组件， 并且是表单数据真实的唯一来源。非受控组件是由 DOM 处理表单数据的地方，而不是在 React 组件中. 尽管非受控组件通常更易于实现，因为只需使用refs即可从 DOM 中获取值，但通常建议优先选择受控制的组件，而不是非受控制的组件。这样做的主要原因是受控组件支持即时字段验证，允许有条件地禁用/启用按钮，强制输入格式。21、如何避免组件的重新渲染？React 中最常见的问题之一是组件不必要地重新渲染。 React 提供了两个方法，在这些情况下非常有用： 1.React.memo():这可以防止不必要地重新渲染函数组件 2.PureComponent:这可以防止不必要地重新渲染类组件 这两种方法都依赖于对传递给组件的props的浅比较，如果 props 没有改变，那么组件将不会重新渲染。 虽然这两种工具都非常有用，但是浅比较会带来额外的性能损失，因此如果使用不当，这两种方法都会对性能产生负面影响。 通过使用 React Profiler，可以在使用这些方法前后对性能进行测量，从而确保通过进行给定的更改来实际改进性能。22、如何避免在React重新绑定实例(解决this指向)？有几种常用方法可以避免在 React 中绑定方法： 1)将事件处理程序定义为内联箭头函数 2)使用箭头函数来定义方法 3)使用带有 Hooks 的函数组件23、React组件通信如何实现?React组件间通信方式: 1.父组件向子组件通讯: 父组件可以向子组件通过传 props 的方式，向子组件进行通讯 2.子组件向父组件通讯: props+回调的方式,父组件向子组件传递props进行通讯，此props为作用域为父组件自身的函数，子组件调用该函数，将子组件想要传递的信息，作为参数，传递到父组件的作用域中 3.兄弟组件通信: 找到这两个兄弟节点共同的父节点,结合上面两种方式由父节点转发信息进行通信 4.跨层级通信: Context设计目的是为了共享那些对于一个组件树而言是“全局”的数据，例如当前认证的用户、主题或首选语言,对于跨越多层的全局数据通过Context通信再适合不过 5.发布订阅模式: 发布者发布事件，订阅者监听事件并做出反应,我们可以通过引入event模块进行通信 6.全局状态管理工具: 借助Redux或者Mobx等全局状态管理工具进行通信,这种工具会维护一个全局状态中心Store,并根据不同的事件产生新的状态24、React如何进行组件/逻辑复用?1)高阶组件: (1)属性代理 (2)反向继承2)渲染属性3)react-hooks25、redux的工作流程?首先，我们看下几个核心概念： 1.Store：保存数据的地方，你可以把它看成一个容器，整个应用只能有一个Store。 2.State：Store对象包含所有数据，如果想得到某个时点的数据，就要对Store生成快照，这种时点的数据集合，就叫做State。 3.Action：State的变化，会导致View的变化。但是，用户接触不到State，只能接触到View。所以， 4.State的变化必须是View导致的。Action就是View发出的通知，表示State应该要发生变化了。 5.Action Creator：View要发送多少种消息，就会有多少种Action。如果都手写，会很麻烦，所以我们定义一个函数来生成Action，这个函数就叫Action Creator。 6.Reducer：Store收到Action以后，必须给出一个新的State，这样View才会发生变化。这种State的计算过程就叫做Reducer。Reducer是一个函数，它接受Action和当前State作为参数，返回一个新的State。 7.dispatch：是View发出Action的唯一方法。然后整个工作流程： (1)首先，用户（通过View）发出Action，发出方式就用到了dispatch方法。 (2)然后，Store自动调用Reducer，并且传入两个参数：当前State和收到的Action，Reducer会返回新的State。 (3）State一旦有变化，Store就会调用监听函数，来更新View。26、redux中如何进行异步操作?当然,我们可以在componentDidmount中直接进行请求无须借助redux. 但是在一定规模的项目中,上述方法很难进行异步流的管理,通常情况下我们会借助redux的异步中间件进行异步处理. redux异步流中间件其实有很多,但是当下主流的异步中间件只有两种redux-thunk、redux-saga，当然redux-observable可能也有资格占据一席之地,其余的异步中间件不管是社区活跃度还是npm下载量都比较差了。