1. 说说React生命周期中有哪些坑?如何避免?
2. 说说Real diff算法是怎么运作的?
3. 调和阶段setState干了什么?
4. 说说redux的实现原理是什么,写出核心代码?
5. React合成事件的原理?
React
并不是将click事件绑在该div
的真实DOM
上,而是在document
处监听所有支持的事件,当事件发生并冒泡至document
处时,React
将事件内容封装并交由真正的处理函数运行。
收集的事件放在dispatchQueue数组中,而冒泡和捕获的区别在于执行时机和顺序,那么我们只需要对数组按照不同顺序循环执行即可
首先会在fiber节点进入render阶段的complete阶段时,将事件监听绑定在root上。然后调用ensureListeningTo进行事件绑定,生成事件合成对象、收集事件、触发真正的事件。
6. React组件之间如何通信?
1.父组件向子组件通讯:
父组件可以向子组件传入props
的方式,向子组件进行通讯。
2.子组件向父组件通讯:props
+回调的方式,父组件向子组件传递props
进行通讯,此props
为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中。
3.兄弟组件通信:
兄弟组件之间的传递,则父组件作为中间层来实现数据的互通,通过使用父组件传递
例:组件A – 传值 --> 父组件 – 传值 --> 组件B
4.跨层级通讯:
Context
设计⽬的是为了共享那些对于⼀个
组件树⽽⾔是“全局”的数据,使用context
提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据
例如当前认证的⽤户、主题或⾸选语⾔,对于跨越多层的全局数据通过 Context
通信再适合不过。
5.发布订阅者模式:
发布者发布事件,订阅者监听事件并做出反应,我们可以通过引⼊event
模块进⾏通信。
6.全局状态管理工具:
借助Redux
或者Mobx
等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store
,并根据不同的事件产⽣新的状态。
链接:React组件之间如何通信?
7. 为什么react元素有一个$$type属性?
目的是为了防止 XSS 攻击
。因为 Synbol
无法被序列化,所以 React
可以通过有没有 $$typeof
属性来断出当前的 element
对象是从数据库来的还是自己生成的。
如果没有 $$typeof
这个属性,react
会拒绝处理该元素。
8. 说说Connect组件的原理是什么?
connect
是一个高阶函数,它真正连接 Redux
和 React
,包在我们的容器组件的外一层,接收上面 Provider
提供的 store
里面的 state
和 dispatch
,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。
原理:
首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入wrapWithConnect,这样就生产出一个经过包裹的Connect组件,该组件具有:
(1)通过props.store获取祖先Component的store
(2)props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component
(3)componentDidMount时,添加事件this.store.subscribe(this.handleChange),实现页面交互
(4)shouldComponentUpdate时判断是否有避免进行渲染,提升页面性能,并得到nextState
(5)componentWillUnmount时移除注册的事件this.handleChange
9. 说说你对fiber架构的理解?解决了什么问题?
解决的问题:JavaScript
引擎和页面渲染引擎两个线程是互斥的,当其中一个线程执行时,另一个线程只能挂起等待;如果 JavaScript
线程长时间地占用了主线程,那么渲染层面的更新就不得不长时间地等待,界面长时间不更新,会导致页面响应度变差,用户可能会感觉到卡顿
理解:
React Fiber
是对 React
做出的一个重大改变与优化,是对 React
核心算法的一次重新实现
主要做了:
为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行
10. 说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
理解:
中间件是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的
Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理
本质上一个函数,对store.dispatch方法进行了改造,在发出 Action和执行 Reducer这两步之间,添加了其他功能
常用中间件:
redux-thunk
:用于异步操作
redux-logger
:用于日志记录
实现原理:
所有中间件被放进了一个数组chain
,然后嵌套执行,最后执行store.dispatch
。可以看到,中间件内部(middlewareAPI
)可以拿到getState
和dispatch
这两个方法内部会将dispatch
进行一个判断,然后执行对应操作
11. React性能优化的手段有哪些?
12. 说说你对事件循环event loop的理解?
14. 数组常用方法及作用,至少15个?
1.Array.length:返回或设置一个数组中的元素个数
2.Array.from() :对伪数组或可迭代对象(包括arguments,Array,Map,Set,String…)转换成数组对象
3.Array.isArray():用于确定传递的值是否是一个 Array
4.concat():方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
5.every(callback):方法测试数组的所有元素是否都通过了指定函数的测试
6.filter():创建一个新数组, 其包含通过所提供函数实现的测试的所有元素
7.find():返回数组中满足提供的测试函数的第一个元素的值
8.forEach():方法对数组的每个元素执行一次提供的函数
9.includes():用来判断一个数组是否包含一个指定的值,如果是,酌情返回 true或 false
10.indexOf():返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1
11.join():将数组(或一个类数组对象)的所有元素连接到一个字符串中
12.lastIndexOf():返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果 不存在则返回 -1。从数组的后面向前查找
13.map():创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果
14.pop():从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度
15.push():将一个或多个元素添加到数组的末尾
16.reduce():累加器和数组中的每个元素(从左到右)应用一个函数
17.shift():从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度
18.slice():返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象
19.some():测试数组中的某些元素是否通过由提供的函数实现的测试。
20.sort():当的位置对数组的元素进行排序,并返回数组。
21.splice():通过删除现有元素和/或添加新元素来更改一个数组的内容
22.toString():返回一个字符串,表示指定的数组及其元素
23.unshift():将一个或多个元素添加到数组的开头,并返回新数组的长度
24.toLocaleString():返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 “,”)隔开
15. React render方法的原理,在什么时候会触发?
原理:
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件
render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新dom树
触发时机:
类组件调用 setState
修改状态
函数组件通过useState hook
修改状态
一旦执行了setState
就会执行render
方法,useState
会判断当前值有无发生改变确定是否执行render
方法,一旦父组件发生渲染,子组件也会渲染
16. 说说你对vue中mixin的理解?
mixin是一种类,在vue中就是js文件,主要的作用是作为功能模块引用。因为在项目中,可能不同组件会有相同的功能,比如控制元素的显示和隐藏,如果他们的变量和规则也完全相同的话,就可以把这个功能单独提取出来,放在mixin.js中,再引入,就可以实现一样的功能了。引入的方法也分为全局混入和局部混入,局部混入就是在每个组件中引入,全局混入就是在main.js中通过Vue.mixin()引入。
17. for…in循环和for…of循环的区别?
for...in 循环:只能获得对象的键名,不能获得键值
for…in循环有几个缺点
①数组的键名是数字,但是for…in循环是以字符串作为键名“0”、“1”、“2”等等。
②for…in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
③某些情况下,for…in循环会以任意顺序遍历键名。
for…in循环主要是为遍历对象而设计的,不适用于遍历数组。
for...of 循环:允许遍历获得键值
for…of循环
①有着同for…in一样的简洁语法,但是没有for…in那些缺点。
②不同于forEach方法,它可以与break、continue和return配合使用。
③提供了遍历所有数据结构的统一操作接口
18. Js数据类型判断都有哪几种方式?至少说出5种?它们的区别是什么?
1. typeof
判断
typeof
返回的类型都是字符串形式
2. Constructor
实例constructor
属性指向构造函数本身constructor
判断方法跟instanceof
相似,但是constructor
检测Object
与instanceof
不一样,constructor
还可以处理基本数据类型的检测,不仅仅是对象类型
3. Instanceof
instanceof
可以判类型是否是实例的构造函数
instanceof
后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。
4. Object.prototype.toString.call()
判断类型的原型对象是否在某个对象的原型链上
5. 通过object
原型上的方法判断
比如array.isArray()
来判断是不是一个数组
6. ===(严格运算符)
通常出现在我们的条件判断中,用来判断数据类型的话就会非常的有局限性,比如判断一个变量是否为空,变量是否为数据等
19. 说说你对Object.defineProperty()的理解?
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
该方法接受三个参数
- 第一个参数是
obj
:要定义属性的对象, - 第二个参数是
prop
:要定义或修改的属性的名称或Symbol
, - 第三个参数是
descriptor
:要定义或修改的属性描述符
函数的第三个参数 descriptor
所表示的属性描述符有两种形式:数据描述符和存取描述符。
- 数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。
- 存取描述符是由
getter
函数和setter
函数所描述的属性。
一个描述符只能是这两者其中之一;不能同时是两者。
这两种同时拥有下列两种键值:configurable
: 是否可以删除目标属性或是否可以再次修改属性的特性(writable
, configurable
, enumerable
)。设置为true
可以被删除或可以重新设置特性;设置为false
,不能被可以被删除或不可以重新设置特性。默认为false
。enumerable
: 当且仅当该属性的 enumerable
键值为 true
时,该属性才会出现在对象的枚举属性中。默认为 false
。