目录
1.说说React生命周期中有哪些坑?如何避免?
2.说说Real diff算法是怎么运作的?
3.调和阶段setState干了什么?
4.说说redux的实现原理是什么,写出核心代码?
5.React合成事件的原理?
6.React组件之间如何通信?
7.为什么react元素有一个$$type属性?
8.说说Connect组件的原理是什么?
9.说说你对fiber架构的理解?解决了什么问题?
10.说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
11.React性能优化的手段有哪些?
12.说说你对事件循环event loop的理解?
13.前端跨域的解决方案?
14.数组常用方法及作用,至少15个?
15.React render方法的原理,在什么时候会触发?
16.说说你对vue中mixin的理解?
17.for…in循环和for…of循环的区别?
18.Js数据类型判断都有哪几种方式?至少说出5种?它们的区别是什么?
19.说说你对Object.defineProperty()的理解?
20.说说你对webSocket的理解?
react生命周期中的坑:
componentWillMount在ssr中这个方法将会被重复触发很多遍同时在这里如果绑定事件,将如法解绑,会导致内存泄漏,变得不够安全高效逐步废弃
ComponentWillReceiveProps外部组件多次频繁的更新传入多次不同的props,会导致不必要的异步请求
ComponentWillUpdate更新前记录Dom状态,可能会做一些处理,与componentDidUpdate相隔时间如果过长,会导致状态不可信
如何避免
react中新的生命周期已经做出了改变,我们可以使用
getDerivedStateFromProps函数 替换 componentWillMount和componentWillReceiveProps生命周期函数
用getSnapshotBeforeUpdate函数替换componentWillUpdate方法,避免和componentDidUpdate函数中获取数据不一致的问题
第一次render在执行的时候会将第一次虚拟dom做一次缓存,第二次渲染的时候后会将新的虚拟dom和老的虚拟dom进行对比。
这个对比的过程就是diff算法,在dom主要更新的时候通过diff算法可以计算出虚拟dom中真正变化的部分,从而只针对变化的部分进行部分更新渲染,避免造成性能浪费
为了优化diff算法,react中对普通的diff算法进行了三大策略:
Tree diff:在对比时遇到同一类型的组件遵循tree diff,进行层级对比,对比时一旦遇到不同类型的组件,直接将这个不同的组件判断为脏组件,并且替换该组件和之下所有的子节点
Element diff:是针对同一层级的element节点的
Component diff:是组件间的对比
具体可以看此 链接: https://blog.csdn.net/weixin_72081046/article/details/128147119
代码中调用setState函数之后react就会将传入的参数对象与组件当前的状态合并,然后去触发所谓的调和过程,经过调和过程,react会以相对高效的方式根据新的状态进行构建react元素并且着手重新渲染整个ui界面
Redux就是一个实现集中管理的容器,遵循三大原则,单一数据源,state是只读的,使用纯函数来进行修改,需要注意的是redux并不是只应用在react还与其他的界面库一起使用。
工作原理:redux要求我们把数据放在一个state公共存储的空间中,一个组件改变了state里面的数据,其他组件就能感受到state的变化,再来获取store里的数据,从而间接的实现了这些数据传递的功能
使用步骤:创建一个store文件夹,新建一个index.js文件,文件中导入redux的createStore方法,用于创建公共数据区域,创建一个reducer纯函数,接收两个参数state、action分别表示数据和操作state的方法,返回state数据给组件页面,把reducer作为createStore的参数抛出在需要使用的页面导入store文件,通过store.getState获取数据,通过store.dispatch触发action修改state数据,使用store.subscrible方法监听store的改变,避免数据不更新
合成事件就是不在浏览器本身触发的事件,自己创建和触发的事件
原理:首先会在fiber节点进入render阶段的component阶段的时候,将事件监听绑定在root上,然后调用ensureListeningTo事件绑定,生成事件合成对象,收集事件,触发真正的事件
React组件通信分为:父传子通信、子传父通信、非父子组件通信
父传子:在父组件中的子组件标签上绑定自定义属性,挂载传递的数据 子组件中props接收传递的数据,直接使用即可
子传父:父组件中的子组件标签上绑定一个属性,传递一个方法给子组件 子组件中通过props接收这个方法,直接调用,传递相应的参数即可
非父子组件:可以使用状态提升(中间人模式)、context状态树传参
状态提升(中间人模式):react中的状态提升概括来说就是将多个组件需要共享的状态提升到离它们最近的父组件,在父组件上改变这个状态,然后通过props分发给子组件
Context状态树传参:在父组件中我们通过createContext()创建一个空对象,在父组件的最外层我们使用Provider包裹数据,通过value绑定要传递的对象数据
在嵌套的子组件中,我们有两种方式获取数据:
我们可以使用Customer标签,在标签中绑定一个箭头函数,函数的形参context就是value传递的数据
Class组件中我们可以定义static contextType=context对象,组件中直接使用this.context获取数据
因为json不支持symbol类型,所以用户即使提交了message的信息,到最后服务器端也不会保存$$typeof的属性,而在渲染的时候,react会检测是否有 $ $typeof属性,如果没有这个属性则会拒绝处理该元素
链接: http://t.csdn.cn/CUqFT
链接: http://t.csdn.cn/MEctk
Redux中,中间件就是放在dispatch过程,在分发action进行拦截处理
当action发出之后,reducer立即算出state,整个过程是一个同步的操作。如果需要支持异步操作,这个过程就可以用上中间件,其本质上就是一个函数,对store.dispatch方法进行了改造,在发出action和执行reducer这两步间添加了其他的功能
常用的中间件:redux-thunk:用于异步操作、redux-logger:用于日志记录
中间件都需要通过applyMiddlewares进行注册,作用是将所有的中间件组成一个数组,依次执行,然后作为第二个参数传入到createStore中
Const store = createStore(
Reducer,
applyMiddlewares(thunk,logger)
);
避免使用内联函数
事件绑定方式
懒加载组件
服务端渲染
userMemo(缓存复杂运算的数据结果)
useCallBack(对传递的方法进行缓存,监听数据更新后才会重新调用方法)
虚拟dom(减少了对真实dom的操作)
Js是单线程,也就是在程序运行时只有一个线程在运行,同一时间只能做一件事,为了解决js单线程阻塞的问题,JavaScript用到计算机系统中的事件循环event loop
同步任务进入主线程,异步任务进入任务队列等候,主线程内的任务执行完成后为空,就会去任务队列中读取响应的任务,推入主线程执行这个过程的不断重复就是事件循环
利用jsonp方式来解决跨域:利用script标签没有跨域的限制,网页可以从其他来源动态获取json数据,从而实现跨域
利用cors技术,需要前后端同时支撑,前端浏览器在ie9以上,后端在响应报头上添加access-Control-Allow-Orgin标签,从而允许指定域的站定访问当前域资源
前端使用配置代理
Array.length:返回或设置一个数组中的元素个数 Array.from() :对伪数组或可迭代对象(包括arguments
Array,Map,Set,String…)转换成数组对象 Array.isArray():用于确定传递的值是否是一个 Array
concat():方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
every(callback):方法测试数组的所有元素是否都通过了指定函数的测试
filter():创建一个新数组, 其包含通过所提供函数实现的测试的所有元素
find():返回数组中满足提供的测试函数的第一个元素的值
forEach():方法对数组的每个元素执行一次提供的函数
includes():用来判断一个数组是否包含一个指定的值,如果是,酌情返回 true或 false
indexOf():返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1
join():将数组(或一个类数组对象)的所有元素连接到一个字符串中
lastIndexOf():返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找
map():创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果
pop():从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度
push():将一个或多个元素添加到数组的末尾
reduce():累加器和数组中的每个元素(从左到右)应用一个函数
shift():从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度
slice():返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象
some():测试数组中的某些元素是否通过由提供的函数实现的测试。
sort():当的位置对数组的元素进行排序,并返回数组。
splice():通过删除现有元素和/或添加新元素来更改一个数组的内容
toString():返回一个字符串,表示指定的数组及其元素
unshift():将一个或多个元素添加到数组的开头,并返回新数组的长度
toLocaleString():返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 “,”)隔开
Render函数里面可以编写JSX,转化成createElement这种实行,用于生成虚拟dom,最终转化成真实dom。
在react中,类组件只要执行了setState方法就一定会触发render函数执行,函数组件使用useState更改状态不一定会导致重新render组件的props;
但是如果props的值来自于父组件的state,在这种情况下,父组件state发生了改变就会导致子组件的重新渲染,所以一旦指令setState就会执行render,useState会判断当前值有没有发生改变,确定是否去执行render方法,一旦父组件发生渲染,子组件也就会发生渲染
Vue中的mixin,提供了一种非常灵活的方式,来分发vue组件中的可复用功能,本质上就是一个js对象,他可以包含我们组件中任意功能选项data和methods等,我们只要将共有的功能以对象方式传入mixin选项中,mixin分为局部混入和全局混入
For…in循环:遍历的是数组则输出的是索引,如果遍历的是对象,输出的是对象的属性名,for…in循环需要分析出array中的每个属性,这个操作性能开销很大,用在key已知的数据上是非常不划算的,所以尽量不要使用for…in,除非不清楚要处理哪些属性,例如JSON对象这样的情况
For…of循环:循环一次,就要检查一下数组的长度,读取属性要比局部变量慢,尤其是当array里面存放的都是dom元素,因为每次读取都会扫描页面上的选择器相关元素,速度会大大降低
通过原型链判断:实例的__proto__属性指向其构造函数的原型对象
Constructor:实例constructor属性指向构造函数本身
Instanceof:instanceof可以判类型是否是实例的构造函数
isPrototypeof:判断类型的原型对象是否在某个对象的原型链上
通过object原型上的方法判断:比如array.isArray()来判断是不是一个数组
Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性
Object.defineProperty(obj, prop, desc)
参数讲解
obj 需要定义属性的当前对象
prop 当前需要定义的属性名
desc 属性描述符
一般通过为对象的属性赋值的情况下,对象的属性可以修改也可以删除,但是通过Object.defineProperty()定义属性,通过描述符的设置可以进行更精准的控制对象属性。
webSocket,是一种网络传输协议,位于OSI模型的应用层,可在TCP连接上进行全双工通信,能更好的节省服务器资源和带宽,并达到实时通信的效果
客户端和服务器端只需要完成一次握手,两者之间就可以创建持久性的链接,并进行双向数据传输
webSocket优点:有较少的控制开销、更好的二进制支持、支持扩展、更好的压缩效果、保持创连接的状态
Websocket的应用应用场景大概有:弹幕、媒体聊天、协同编辑、基于位置的应用、体育实况更新、股票基金报价实时更新