1.vue双向绑定的原理?
mvvm场景:数据操作比较多的场景,需要大量使用DOM元素时,采用mvvm的开放方式,会更加便捷,让开发者更多的经历放在数据的变化上,解放繁琐的DOM元素
- MVVM 模型,
- M 数据 从后台获取的商品数据
- V 视图 就是写好的页面,每一个div,每一个input 都是视图
- VM 视图模型,
- 数据发生变化,通过视图模型会改变视图的显示,视图上的改变,也会通过视图模型进而影响数据的变化
- 核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法。
2.vue的生命周期有哪些
- beforeCreate(创建前)
- created(创建后)
- beforeMount(载入前)
- mounted(载入后)
- beforeUpdate(更新前)
- updated(更新后)
- beforeDestroy(销毁前)
- destroyed(销毁后)
mounted 真实dom挂载完成 updated只要data数据被改变 就会自动更新触发 destroy销毁全局计时器和自定义事件
如果使用了keep-alive会在多两个:activated、deactivated当组件初次加载会执行前4个生命周期,分别为: beforeCreate、created、beforeMount、mounted
3.v-if 和v-show有什么区别?
- 相同点:都可以控制dom元素的显示和隐藏
不同点:v-show只是改变display属性,dom元素并未消失,切换时不需要重新渲染页面
v-if直接将dom元素从页面删除,再次切换需要重新渲染页面
如果需要频繁的进行元素的显示和隐藏使用v-show性能更好
4.async await 是什么?它有哪些作用?
- async await 是ES7的新增,async用于声明一个函数,await用于等待一个异步方法执行完成。
- async函数返回的是一个promise对象,可以用.then方法添加回调函数,在函数执行的中,一旦遇到await就回先返回,等到这个异步操作完成之后,它再进行函数体内后面的这个语句
5、数组常用的方法?哪些方法会改变原数组,哪些不会
会改变原数组:
pop (删除数组的最后一个元素并返回删除的元素)
push(向数组的末尾添加一个或更多元素,并返回新的长度)
shift(删除并返回数组的第一个元素)
unshift(向数组的开头添加一个或更多元素,并返回新的长度)
reverse(反转数组的元素顺序)
sort(对数组的元素进行排序)
splice(用于插入、删除或替换数组的元素)
不会改变原数组:
concat---连接两个或更多的数组,并返回结果。
every---检测数组元素的每个元素是否都符合条件。
some---检测数组元素中是否有元素符合指定条件。
filter---检测数组元素,并返回符合条件所有元素的数组。
indexOf---搜索数组中的元素,并返回它所在的位置。
join---把数组的所有元素放入一个字符串。
toString---把数组转换为字符串,并返回结果。
lastIndexOf---返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
map---通过指定函数处理数组的每个元素,并返回处理后的数组。
slice---选取数组的的一部分,并返回一个新数组。
valueOf---返回数组对象的原始值
6.什么是原型链?
每一个实例对象上有一个proto属性,指向的构造函数的原型对象,构造函数的原型对象也是一个对象,也有proto属性,这样一层一层往上找的过程就形成了原型链。
7.什么是闭包?闭包有哪些优缺点?
- 概念:函数嵌套函数,内部变量能访问外部变量,这个变量称为自由变量
- 解决的问题:保存变量
- 带来的问题:会造成内存泄漏问题
- 闭包的应用:防抖节流
8.es6有哪些新特性?
- 新增模板字符串
- 箭头函数
- for-of(用来遍历数据—例如数组中的值。)
- ES6 将 Promise 对象纳入规范,提供了原生的 Promise 对象。
- 增加了 let 和 const 命令,用来声明变量。
- 还有就是引入 module 模块的概念
9.v-for 循环为什么一定要绑定key ?
给每个dom元素加上key作为唯一标识 ,diff算法可以正确的识别这个节点,使页面渲染更加迅速!
10.组件中的data为什么要定义成一个函数而不是一个对象?
每个组件都是 Vue 的实例。组件共享 data 属性,当 data 的值是同一个引用类型的值时,改变其中一个会影响其他
11.常见的盒子垂直居中的方法有哪些请举例3种?
利用子绝父相定位方式来实现
<style>
.container{
width: 300px;
height: 300px;
position: relative;
}
.conter{
width: 100px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -50px;
}
</style>
利用Css3的transform,可以轻松的在未知元素的高宽的情况下实现元素的垂直居中。
<style>
.container{
position: relative;
}
.conter{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
</style>
flex
<style>
.container{
display: flex;
justify-content: center;
align-items: center;
}
.conter{
}
</style>
12.js数据类型有哪些,区别是什么
- 基本类型:string,number,boolean,null,undefined,symbol,bigInt
- 引用类型: object,array、function、date
- 基本类型存储在栈中,空间小,操作频繁
- 引用数据类型存放在堆中,它的地址在栈中,一般我们访问就是它的地址
symbol是es6引入新的原始数据类型Symbol,表示独一无二的值
13.什么是同源策略
所谓同源策略就是浏览器的一种安全机制,来限制不同源的网站不能通信(域名、协议、端口号相同)
14.promise是什么,有什么作用
- promise 是一个对象, 可以从改变对象获取异步操作信息
- 他可以解决回调地狱的问题,也就是异步深层嵌套问题
15.什么是递归,递归有哪些优缺点?
- 递归:如果函数在内部可以调用其本身,那么整函数就是递归函数,简单理解:函数内部自己调用自己,这个函数就是递归函数,
- 优点:机构清晰,可读性强
- 缺点:效率低,调用站可能溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的内容粮食有限的。当调用的层次太多时,就会超出栈的容量,从而导致栈溢出
16. var、let和const 的区别是什么
- var: 存在变量提升;存在变量覆盖,已经被定义且赋值的变量,如果再次被赋值,则以后一次值为准;没有块级作用域;
- let 命令不存在变量提升,如果在 let 前使用,会导致报错
- 如果块区中存在 let 和 const 命令,就会形成封闭作用域
- 不允许重复声明;不存在变量提升和变量覆盖;有块级作用域;
- const定义的是常量,不能修改,但是如果定义的是对象,可以修改对象内部的数据
17.vue性能优化
- 函数式组件
- 路由懒加载
- v-for要绑定key key是虚拟dom唯一标志,能帮vue高效的动态渲染页面,渲染页面时会使diff算法,会比较新旧dom,在比较时只比较同一级,不进行跨级比较,key发生变化节点进行销毁,并且是子节点先销毁。
- computed缓存数据和watch keep-alive缓存组件
- v-if和v-for不要同时使用,v-show是display,销毁是display-none.v-if为true创建.false销毁
- 设计vue响应式数据时不能设计太深.会做全量递归的计算.
- 组件的颗粒度不能设计太细.合理划分.层级越深性能消耗越大
- 防抖节流
- ui组件库按需引入
18..mvvm和mvc
- MVC:M(model数据)、V(view试图),C(controlle控制器)缺点是前后端无法独立开发,必须等后端接口做好了才可以往下走;前端没有自己的数据中心,太过依赖后台
- MVVM:M(model数据)、V(view试图)、VM(viewModel控制数据的改变和控制试图)html部分相当于View层,可以看到这里的View通过通过模板语法来声明式的将数据渲染进DOM元素,当ViewModel对Model进行更新时,通过数据绑定更新到View。 Vue实例中的data相当于Model层,而ViewModel层的核心是Vue中的双向数据绑定,即Model变化时VIew可以实时更新,View变化也能让Model发生变化
- MVVM与MVC最大的区别就是:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变
- m(数据层)v(视图层)vm(数据视图交互层)简化了大量dom操作 ,只用于单页面,通过数据来显示视图层而不是节点操作。
- mvc还需要获取dom,使页面渲染性能低且加载速度慢
- 面试可以说的项目优化:
- 设计vue响应式数据时不能设计太深.会做全量递归的计算.
- 组件的颗粒度不能设计太细.合理划分.层级越深性能消耗越大
19.路由模式:hash和history
- 实现的功能:
- 改变url且不让浏览器向服务器发请求
- 检测url的变化
- 截获url地址 并解析出需要的信息匹配路由规则
- hash基于url传参 会有体积限制,不会包括在http请求中对后端完全没有影响,改变hash不会重新加载页面; history可以在url里放参数 还可以将数据存放在一个特定对象中.history模式浏览器白屏解决方法是在服务端加一个覆盖所有的情况候选资源,必须要服务端在服务器上有对应的模式才能使用,如果服务器没配置,可以先使用默认的hash。
21.常用的块与行属性内标签有哪些?有什么特征
- 块标签:div、h1~h6、ul、li、table、p、br、form。
- 特征:独占一行,换行显示,可以设置宽高,可以嵌套块和行
- 行标签:span、a、img、textarea、select、option、input。
- 特征:只有在行内显示,内容撑开宽、高,不可以设置宽、高(img、input、textarea等除外)
22.== 和 ===的区别
- ==是非严格意义上的相等
- 值相等就相等
- ===是严格意义上的相等,会比较两边的数据类型和值大小
- 值和引用地址都相等才相等
23.严格模式的限制
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用 with 语句
- 禁止 this 指向全局对象
24.git
git命令
- git init 初始化仓库
- git clone 克隆
- git status 检查文件状态
- git add. 将文件添加到暂存区
- git commit -m 描述信息
分支明细
(1)主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。
(2)开发分支(develop):作为开发的分支,基于 master 分支创建。
(3)功能分支(feature):作为开发具体功能的分支,基于开发分支创建
分支命令
(1)git branch 查看分支
(2)git branch 分支名称 创建分支
(3)git checkout 分支名称 切换分支
(4)git merge 来源分支 合并分支 (备注:必须在master分支上才能合并develop分支)
(5)git branch -d 分支名称 删除分支(分支被合并后才允许删除)(-D 强制删除)
暂时保存更改(1)存储临时改动:git stash
(2)恢复改动:git stash pop
25.tcp和udp协议
- tcp安全性更高 http协议是建立在tcp基础上的
- udp效率比tcp高 容易丢数据
26.vuex的五种状态
- mutations(修改state里面的数据,但是他只能执行同步的操作,异步必须写在action里面)
- state(放数据)
- action(执行异步操作)
- getter(计算属性)
- moudel(允许将单一store拆分多个store并且同时保存在单一的状态中)
传递过程
页面通过mapAction异步提交事件到action。action通过commit把对应参数同步提交到mutation,mutation会修改state中对应的值。 最后通过getter把对应值跑出去,在页面的计算属性中,通过,mapGetter来动态获取state中的值
27.什么是防抖和节流,js 如何处理防抖和节流
- 防抖:触发事件后,在n秒内,事件只执行一次,如果在n秒内又触发了事件,则会重新计算函数的执行时间。比如点击按钮,2秒后调用函数,结果在1.5秒的时候又点了,则会重新计算2秒后在调用函数。
- 应用场景:下拉触底加载下一页。
- 节流:连续发生的事件在n秒内,只执行为一次
- 应用场景比较多的是:搜索查询
首先 防抖就是触发下一个事件时停止掉上一个事件
节流是 触发当前事件需要在上一个事件结束以后
通过设置节流阀(定时器)
28.什么是重绘和回流
- 重绘:当元素内容以及布局没有发生改变,只是元素外观发生改变(background-color),就会重绘
- 回流:当一部分内容或者布局发生了改变,重新构建页面就会产生回流
- 产生回流一定会造成重绘,但是重绘不一定造成回流
29.Css优先级
!importent>行内> id> 类,伪类,属性>标签,伪元素选择器 > 继承和通配符
30.如何解决盒子塌陷
父盒子设置上边距
overflow:hidden
子盒子脱标
父盒子上 padding
31.清楚浮动的方法
一共有5中方法
父盒子设置高度
overflow:hidden
伪元素
双伪元素
在父盒子末尾添加一个空盒子,设置 clear:both
32.Split()和 join()的区别?
- split 字符串转换为数组,参数为以某个字符串分隔
- join 数组转换为字符串 参数表示转换为的字符串以什么连接
33.数组去重
1.利用双重for循环,再利用数组方法splice方法去重(es5常用)
2.set去重:准备一个数组,数组解构newset,再准备一个函数存放数组的变量作为函数的判断值,return
Array.from(new set(arr))即可
3.数组方法indexof
4.数组方法sort Obj[a]-Obj[b]
34.什么原因会造成内存泄露
- 全局变量使用不当(没有声明的变量)
- 闭包使用不当
- 定时器/延时器没有清理
- 没有清理的DOM元素引用(dom清空或删除时,事件未清除)
35.第一次加载页面会触发哪几个钩子函数?
beforeCreate
created 数据初始化完成,方法也调用,但是DOM未渲染
beforeMount
mounted DOM和数据挂在完成
36.Vuex 的 5 个核心属性是什么?
- state => 基本数据
- getters => 从基本数据(state)派生的数据,相当于state的计算属性
- mutations => 提交更改数据的方法,同步!
- actions => 像一个装饰器,包裹mutations,使之可以异步。
- modules => 模块化Vuex
- 简述vuex数据传递过程
- 页面通过mapAction异步提交事件到action。action通过commit把对应参数同步提交到mutation,mutation会修改state中对应的值。 最后通过getter把对应值跑出去,在页面的计算属性中,通过,mapGetter来动态获取state中的值
37.get和post区别
相同点
get请求和post请求底层都是基于TCP/IP协议实现的,使用二者中的任意一个,都可以实现客户端和服务器端的双向交互
最本质的区别
- 约定和规范:
- 规范:定义GET请求是用来获取资源的,也就是进行查询操作的,POST请求是用来传输实体对象的, 用于 增删改操作
- 约定:GET请求 将参数拼接到URL上进行参数传递 POST请求将参数写入请求正文中传递
非本质区别
- 缓存不同 ,get会缓存
- 参数长度限制不同,get请求的参数是通过URL传递的,而URL的长度是有限制的,通常为2K;post请求参数存放在请求正文中,没有大小限制
- 回退和刷新不同,get请求可以直接回退和刷新,不会对用户和程序产生影响;post请求如果直接回滚和刷新,数据将会再次提交
- 历史记录不同,get请求的参数会保存在历史记录中,post请求的参数不会
- 书签不同,get请求的地址可以被收藏为书签,post不会
38.跨域
1. 跨域原因:浏览器出于安全考虑保护资源,同源策略。(协议、域名、端口号)
2.解决跨域:
- jsonP 但只能使用get 原理-将请求的接口设置给script标签的src属性传递一个函数给后台实现跨域。后台响应的是一个函数调用
- cors:最常用。
- 反向代理:本地前端发送到本地后端,不会跨域,(同源)本地后端接收请求后转发到其他服务器(服务器和服务器之间不会跨域)代理是需要路径中的特殊标志。
39.三种存储的区别
共同点: 都是保存在浏览器端、且同源的
- cookie 设置过期时间删除,即使窗口或浏览器关闭(加密字符,用于数据的请求)
- localStorage 存储量大,存储持久数据,浏览器关闭后数据不会丢失除非手动删除
- sessionStorage临时存储,关闭浏览器是存储内容自动清除
存储大小:
- cookie 数据大小不能超过4k
- sessionStorage和localStorage虽然也有存储大小的限制,单笔cookie大得多,可达到5m或更大
40.dom如何实现浏览器内多个标签页之间的通信
- websocket.SharedWoeket;
- 也可以调用localStorage、cookies等本地存储方式;localStorage另一个浏览器上下文里被添加、修改或删除时,他都会触发一个事件,我们通过监听事件,控制他的值进行页面信息通信;
- 注意quirks:Safari在无痕模式下设置localStorage值时会抛出,quotaExceededError的异常
41.请说出vue.cli项目中src目录每个文件夹和文件的用法?
- assets文件夹是放静态资源;
- components是方组件;
- router是定义路由相关的配置
- view是视图
- app.vue是一个应用主组件
- main.js是入口文件
42.$route和$router的区别
router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。。。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。
route相当于当前正在跳转的路由对象。。可以从里面获取name,path,params,query等
43.虚拟dom实现原理
- 用JavaScript对象模拟真实DOM树,对真实DOM进行抽象
- diff算法:比较两棵虚拟树的差异
- pach算法:将两个虚拟DOM对象的差异应用到真实的DOM树
44.箭头函数和普通函数的区别
- 箭头函数没有原型,原型是undefined
- 箭头函数this指向全局对象,而函数指向引用对象
- call,apply,bind方法改变不了箭头函数的指向
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
不可以当作构造函数,也就是说不可以使用new命令,否则会报错
不可以使用arguments对象,该对象在函数体内不存在,如果要用可以使用Rest参数代替
不可以使用yield命令,因此箭头函数不能用作Generator函数
45.怎样理解vue单项数据流
数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原数据进行修改
46.slot插槽
- slot插槽,可以理解为slot在组件模板中提前占据了位置,当复用组件时,使用相关的slot标签时,标签里的内容就会自动替换组件模板中对应slot标签的位置,作为承载分发内容的出口
- 主要作用是:复用和扩展组件,做一些定制化组件的处理
47.vue常见指令
- v-model 多用于表单元素实现双向数据绑定
- v-bind:简写为:,动态绑定一些元素的属性,类型可以是:字符串、对象或数组。
- v-on:click 给标签绑定函数,可以缩写为@,例如绑定一个点击函数 函数必须写在methods里面
- v-for 格式: v-for="字段名 in(of) 数组json" 循环数组或json
- v-show 显示内容
- v-else指令:和v-if指令搭配使用,没有对应的值。当v-if的值false,v-else才会被渲染出来
- v-if指令:取值为true/false,控制元素是否需要被渲染
- v-else-if 必须和v-if连用
- v-else指令:和v-if指令搭配使用,没有对应的值。当v-if的值false,v-else才会被渲染出来
- v-text 解析文本
- v-html 解析html标签
- v-bind:class 三种绑定方法 1、对象型 '{red:isred}' 2、三元型 'isred?"red":"blue"' 3、数组型 '[{red:"isred"},{blue:"isblue"}]'
- v-once 进入页面时 只渲染一次 不在进行渲染
- v-cloak 防止闪烁
- v-pre 把标签内部的元素原位输出
48.vue中keep-alive 的作用
- < keep-alive >是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
- < keep-alive > 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
49.es6新增特性
新增模版字符串
箭头函数
增加let、const来声明变量
for-of用来遍历数据-例如数组中的值
解构赋值
新增简单数据类型Symbol,独一无二的,不会与其他属性名冲突
将Promise对象纳入规范,提供了原生的Promise对象
50.数组方法汇总
- map 循环遍历数组、返回一个新的数组
- forEach 循环遍历数组,不改变原数组
- push/pop 在数组的末尾添加/删除元素 改变原数组
- unshift/ shift 在数组的头部添加/删除元素,改变原数组
- join 把数组转化为字符串
- some 有一项返回为true,则整体为true
- every 有一项返回为true,则整体为false
- filter 数组过滤
- slice(start, end) 数组截取,包括开头,不包括截取,返回一个新的数组
- splice(start, number, value) 删除数组元素,改变原数组
- indexof/lastindexof: 查找数组项,返回对应的下标
- concat:数组的拼接,不影响原数组,浅拷贝
- sort:数组排序 改变原数组
- reverse: 数组反转,改变原数组
51.项目性能优化方案
减少http请求
减少DNS查询
使用CDN
避免重定向
图片懒加载
路由懒加载
减少DOM元素操作
使用外部js和css
压缩js、css、字体、图片等
使用iconfont字体图标、雪碧图等
避免图片的src为空
把样式表放在link中
把js放在页面的底部
51.项目性能优化方案
forEach方法,是最基本的方法,遍历和循环。
默认有3个参数:分别是遍历的每一个元素item,遍历的索引index,遍历的数组array
map方法,和foreach一致,不同的是会返回一个新的数组,所以callback需要有return返回值,如果没有会返回undefined
52.this指向
this总是指向函数的直接调用者。
如果有new关键字,this指向new出来的对象
在事件中,this指向触发这个事件的对象
53.this指向
在js中,变量和函数的声明会被提升到最顶部执行
函数提升高于变量的提升
函数内部如果用var声明了相同名称的外部变量,函数将不再向上寻找
匿名函数不会提升
54.setTimeout 时间为0, 以及误差的原因
setTimeout,如果时间为0,则会立即插入队列,不是立即执行,等待前面的代码执行完毕。
55.setTimeout 时间为0, 以及误差的原因
区别:
- async是来定义函数的,定义异步函数,打印函数名可以得到一个promise对象,言外之意可以通过这个 函数名称.then 这个方法
- await 后面跟的是任意表达式,一般使用promise的表达式
- async 内部实现,又返回值 成功返回promise.resolve() ,出错返回promise.reject() 返回值用catch捕获
- await 等待后面的promise对象执行完毕,拿到了promise.resolve()的值之后,执行后面的代码。await后面的表达式,能是promise.reject(),所以建议await放在try....catch语句中
- 优点:async和await 属于es7语法。编写方便,提高程序效率,避免了回调地狱
- 补充:promise和async和await的区别
1).promise es6语法,promise中包含catch,async需要自己定义catch
2).promise 提供的方法会多一些,all、race等方法,aync中是没有的。
56.get与post请求有什么区别
- get是从服务器上获取数据,post是向服务器传送数据。
- POST比GET安全,因为数据在地址栏上不可见。
- get方式提交的数据最多只能有1024字节,而post则没有此限制。
- GET使用URL或Cookie传参。而POST将数据放在request BODY中。
- GET与POST都有自己的语义,不能随便混用。
- 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基,本可以无视。而在网 络环境差的情况下,两次包的TCP在验证数据包完整 性上,有非常大的优点。post 发送两次,get 只发送一次。
57.watch和computed的区别
computed能完成的功能,watch都可以完成
watch能完成的小功能,computed不一定能完成。例如:watch可以进行异步操作两个重要小原则:
1. 所有被vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象
2. 所有不被vue管理的函数(定时器的回调、ajax的回调、promise的回调等),最好写成箭头函数,这样this的指向才是vm或组件实例对象
58.打包后 dist 目录过大,解决办法?
1. dist打包生成的文件中有 .map 文件,可以删除。在 vue.config.js文件中配置:productionSourceMap: false
2. 组价和路由使用懒加载、按需引入等
3. 对于文件和图片进行压缩。 安装压缩组件: compression-webpack-plugin
安装后进行导入配置:
1).最小化代码 minisize: true
2).分割代码: splitChunksl
3).超过限定值的文件进行压缩,threshold: 文件大小(字节为单位)
59.vue中的data为什么是一个函数?
实际上就是一个闭包,因为vue是单页面应用,是由很多组件构成,每一个组件中都有一个data,所以通过闭包给每一个组件创建了一个私有的作用域,这样就不会相互影响。
60.vue中的data为什么是一个函数?
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调从而达到数据和视图同步。
61.vue中的data为什么是一个函数?(面试常问)
Vue 中的 data 必须是个函数,因为当 data 是函数时,组件实例化的时候这个函数将会被调用,返回一个对象,计算机会给这个对象分配一个内存地址,实例化几次就分配几个内存地址,他们的地址都不一样,所以每个组件中的数据不会相互干扰,改变其中一个组件的状态,其它组件不变。
简单来说,就是为了保证组件的独立性和可复用性,如果 data 是个函数的话,每复用一次组件就会返回新的 data,类似于给每个组件实例创建一个私有的数据空间,保护各自的数据互不影响
62.什么是JSX?
JSX是一种Javascript的语法扩展,可以很好的描述UI的架构。是React.createElement的语法糖。浏览器不能直接解析JSX文件,需要通过Bable进行转译成js。
63.62.什么是JSX?(react)
虚拟Dom:虚拟Dom是描述真实Dom的js对象。
特点:
(1)处理了浏览器兼容性问题,避免用户操作真实DOM,不容易出错。
(2)内容经过了XSS处理,可以防范XSS攻击。
(3)可以实现跨平台开发。
(4)在更新的时候,比较两棵虚拟DOM树的差异,差异化更新。
延伸题:
- 什么是diff算法?
diff算法,就是用来找出两段文本之间的差异的一种算法。
- vdom为什么用diff算法?
diff算法,就是用来找出两段文本之间的差异的一种算法。
- vdom比真实dom快?
回答:不一定。
在比较性能的时候,要分清楚初始渲染、小量数据更新、大量数据更新这些不同的场合。
无效、无意义的diff是需要浪费性能的,因此有些场景不如直接操作原生DOM性能好。
64.react中类组件和函数组件之间的区别是什么?
相同点:
它们都可以接收属性并且返回React元素。
不同点:
(1)类组件需要创建实例,是基于面向对象的方式编程,函数组件不需要创建实例,接收输入,返回输出,是基于函数编程的思想。
(2)类组件需要创建并且保持实例,会占用一定的内存,函数组件不需要创建实例,可以节约内存占用。
(3)类组件有完整的生命周期,函数组件没有生命周期(现在通过useEffect实现类似生命周期的功能)
(4)类组件通过shouldComponent和pureComponent跳过更新,而函数组件可以通过React.memo跳过更新。
(5)类组件服用逻辑一般用HOC,函数组件可以自定义Hook。
延伸题:
源码如何区分函数组件与类组件?
通过Component.prototype.isReactComponent属性来判断。
65.react中hooks出现的意义?
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
Hooks 优势:
(1)函数组件无 this 问题
(2)自定义 Hook 方便复用状态逻辑
(3)副作用的关注点分离
66.react中了解React Fiber吗?
React Fiber初衷是改变js在浏览器的主线程上长时间执行,会阻塞其他操作,影响用户体验。
Fiber的关键特性:
(1)增量渲染(把渲染任务拆分成块,匀到多帧)
(2)更新时能够暂停,终止,复用渲染任务
(3)给不同类型的更新赋予优先级
(4)并发方面新的基础能力
协调器reconciler :
- Fiber前的 Reconciler 被命名为Stack Reconciler 运作的过程无法中断(持续占用主线程),这样主线程上的布局、动画等周期性任务以及交互响应就无法立即得到处理,影响体验。
- 而新的Reconciler 命名为Fiber Reconciler 每执行一段时间,都会将控制权交回给浏览器,可以分段执行。
Fiber Reconciler 在执行过程中,会分为 2 个阶段 :
(1)render阶段,生成 Fiber 树,得出需要更新的节点信息。这一步是一个渐进的过程,可以被打断。
(2)commit阶段,将需要更新的节点一次过批量更新,这个过程不能被打断。
67.react中requestIdleCallback了解多少?
requestIdleCallback方法将在浏览器的空闲时段内调用的函数排队。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。
window.requestIdleCallback(callback[, options])
// 示例
let handle = window.requestIdleCallback((idleDeadline) => {
const {didTimeout, timeRemaining} = idleDeadline;
console.log(`超时了吗?${didTimeout}`);
console.log(`可用时间剩余${timeRemaining.call(idleDeadline)}ms`);
// do some stuff
const now = +new Date, timespent = 10;
while (+new Date < now + timespent);
console.log(`花了${timespent}ms搞事情`);
console.log(`可用时间剩余${timeRemaining.call(idleDeadline)}ms`);
}, {timeout: 1000});
68.react中setState 同步还是异步?(比较常问)
(1)React生命周期中以及事件处理中,为异步。
(2)原生方法(setTimeout,setInnerval,addEventListener )中是同步 。
- 原理:setState本身并不是异步,只是因为react的性能优化机制体现为异步。在react的生命周期函数或者作用域下为异步,在原生的环境下为同步。 因为每次调用setState都会触发更新,异步操作是为了提高性能,将多个状态合并一起更新,减少re-render调用。
- 性能优化机制:在 React 的 setState 函数实现中,会根据一个变量isBatchingUpdates判断是直接更新 this.state 还是放到队列中。isBatchingUpdates 默认是 false,React 在调用事件处理函数之前会将isBatchingUpdates改为true,造成的后果就是由 React 控制的事件处理过程 setState 不会同步更新 this.state。而原生方法不会被React控制。
69.react中setStateReact-router路由模式?
- hash模式(HashRouter):通过监听 hashchange 事件, 在回调里拿到 window.location.hash 的值。 hash 就是指 url 尾巴后的 # 号以及后面的字符。
- hash模式原理:使用window.location.hash属性及窗口的onhashchange事件,可以实现监听浏览器地址hash值变化,执行相应的js切换网页。 hash指的是地址中#号以及后面的字符,也称为散列值。
- history模式(BrowserRouter): 利用history API实现url地址改变,网页内容改变。
- history模式原理:window.history 属性指向 History 对象,它表示当前窗口的浏览历史。 History 对象保存了当前窗口访问过的所有页面网址。
70.react中React的生命周期?
目前React 16.8+的生命周期分为三个阶段,分别是挂载阶段、更新阶段、卸载阶段。
目前React 16.8+的生命周期分为三个阶段,分别是挂载阶段、更新阶段、卸载阶段。
componentWillMount
componentWillReceiveProps
componentWillUpdate
延伸问题:为什么要删除这三个函数?
答:废弃的三个函数都是在render之前,因为fiber的出现,很可能因为高优先级任务的出现而打断现有任务导致它们会被执行多次。
挂载阶段:
- constructor:构造函数,最新被执行,我们通常在构造函数里初始化state对象或者给自定义方法绑定this。
- getDerivedStateFromProps:static getDerivedStateFromProps(nextProps,prevState),这个是静态方法,当我们接收到新的属性想去修改我们state,可以使用getDerivedStateFromProps(新增生命周期)
- render:render函数是纯函数,只返回需要渲染的东西,不应该包含其它业务逻辑,可以返回原生的DOM、React组件、Fragment、Portals、字符串和数字、Boolean和null等内容
- componentDidMount:组件装载之后调用,此时我们可以获取到DOM节点并操作,比如对canvas,svg的操作,服务器请求,订阅都可以写在这个里面,但是记得在componentWillUnmount中取消订阅
更新阶段:
- getDerivedStateFromProps:此方法在更新挂载阶段都可能会调用
- shouldComponentUpdate:shouldComponentUpdate(nextProps,nextState),有两个参数nectProps和nectState,表示新的属性和变化之后的state,返回一个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true,我们通常利用此声明周期来优化React程序性能
- render:更新阶段也会触发此生命周期
- getSnapShotBeforeUpdate:getSnapshotBeforeUpdate(prevProps,prevState),这个在render方法之后,componentDidUpdate之前调用,有两个参数prevProps,prevState,表示之前的属性和之前的state,这个函数有一个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此生命周期必须与componentDidUpdate搭配使用(新增生命周期)
- componentDidUpdate:componentDidUpdate(prevProps,prevState,snapshot),该方法在getSnapshotBeforeUpdate方法之后被调用,有三个参数prevPropsprevState,snapshot,表示之前的props,之前的state,和snapshot。第三个参数是getSnapshotBeforeUpdate返回的,如果触发某些回调函数时需要用到DOM元素的状态,则将对比或计算过程迁移至getSnapshotBeforeUpdate,然后再componentDidUpdate中统一触发回调或更新状态。
卸载阶段:
- componentWillUnmount:当我们的组件被卸载或者销毁了就回调用,我们可以在这个函数里去清楚一些定时器,取消网络请求,清理无效的DOM元素等垃圾清理工作
71.react中你知道那些hook?
- useState()`,状态管理钩子。通过在函数组件中调用useState,就会创建一个单独的状态。
- useEffect(),副作用钩子。它接收两个参数, 第一个是进行的异步操作, 第二个是数组,用来给出Effect的依赖项
- useContext(),共享钩子。该钩子的作用是,在组件之间共享状态。
- useReducer(),Action 钩子。useReducer() 提供了状态管理,其基本原理是通过用户在页面中发起action,从而通过reducer方法来改变state, 从而实现页面和状态的通信。
- useRef(),获取组件的实例;渲染周期之间共享数据的存储(state不能存储跨渲染周期的数据,因为state的保存会触发组件重渲染)
- useMemo和useCallback:可缓存函数的引用或值,useMemo用在计算值的缓存,注意不用滥用。经常用在下面两种场景(要保持引用相等;对于组件内部用到的object、array、函数等,如果用在了其他 Hook 的依赖数组中,或者作为 props 传递给了下游组件,应该使用useMemo/useCallback)
71.react中你对Time Silce(时间分片)的理解?
- React在渲染(render)的时候,不会阻塞现在的线程
- 如果你的设备足够快,你会感觉渲染是同步的
- 如果你得设备非常慢,你会感觉还算是灵敏的
- 虽然异步渲染,但是你将会看到完整的渲染,而不是一个组件一行行的渲染出来
- 同样书写组件的方式
也就是说,这事React背后在做的事情,对于我们开发者来说,是透明的,具体是什么样的效果呢?
例如,由三个图表,有一个输入框以及上面的三种模式
这个组件非常的巨大,而且在输入框每次输入东西的时候,就回进去一直在渲染。
同步模式:
在同步模式下,我们都知道,我们没输入一个字符,React就开始渲染,当React渲染一颗巨大的树的时候,是非常卡的。所以才会有shouldUpdate的出现。
Debounced模式:
Debounced模式简单的来说,就是延迟渲染,比如,当你输入完以后,在开始渲染所有的变化。这么做的坏处就是,至少不会阻塞用户的输入了,但是依然由非常严重的卡顿。
异步模式:
一部渲染模式就是不阻塞当前线程,继续跑。时间分片正是基于可随时打断、重启Fiber架构,可打断当前任务,优先处理紧急且重要的任务,保证页面的流程运行。
也就是说,这事React背后在做的事情,对于我们开发者来说,是透明的,具体是什么样的效果呢?
例如,由三个图表,有一个输入框以及上面的三种模式
这个组件非常的巨大,而且在输入框每次输入东西的时候,就回进去一直在渲染。
同步模式:
在同步模式下,我们都知道,我们没输入一个字符,React就开始渲染,当React渲染一颗巨大的树的时候,是非常卡的。所以才会有shouldUpdate的出现。
Debounced模式:
Debounced模式简单的来说,就是延迟渲染,比如,当你输入完以后,在开始渲染所有的变化。这么做的坏处就是,至少不会阻塞用户的输入了,但是依然由非常严重的卡顿。
异步模式:
一部渲染模式就是不阻塞当前线程,继续跑。时间分片正是基于可随时打断、重启Fiber架构,可打断当前任务,优先处理紧急且重要的任务,保证页面的流程运行。
72.react中redux的工作流程?
核心概念:
- Store:保存数据的地方,你可以把它看成一个容器,整个应用只能由一个Store>
- State:Store对象包含所有数据,如果想得到某个时点的数据,就要对Store生成快照,这种时点的数据集合,就叫做State。
- Action:State的变化,会导致View的变化。但是,用户接触不到State,只能接触到view。所以,State的变化必须由View导致的。Action就是View发出的通知,表示State应该要发生变化了。
- Action Creator:View要发送多少种消息,就会有多少种Action。如果都手写,会很麻烦,所以我们定义一个函数来生成Action,这个函数就叫Action Creator。
- Reducer:Store收到Action以后,必须给出一个新的State,这样View才会发生变化。这种State的计算过程就叫做Reducer。Reducer是一个函数,他接受Action和当前State作为参数,返回一个新的State。
- dispatch:是Vie发出Action的唯一方法。
工作流程:
(1)首先,用户(通过View)发出Action,发出方式就用到了dispatch方法。
(2)然后,Store自动调用Reducer,并且传入两个参数:当前State和收到的Action,Reducer会返回新的State。
(3)State一旦有变化,Store就回调用监听函数,来更新View。
更多面试资源请咨询