文章目录
- 前端面试题
- 1. props和state相同点和不同点?render方法在哪些情况下会执行?
- 2. shouldComponentUpdate有什么作用?
- 3. 说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?
- 4. react新出来两个钩子函数是什么?和删掉的will系列有什么区别?
- 5. React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历?
- 6. React组件之间如何通信?
- 7. 谈谈你对immutable.js的理解?
- 8. redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?
- 9. redux中同步action与异步action最大的区别是什么?
- 10. redux-saga和redux-thunk的区别与使用场景?
- 11. 在使用redux过程中,如何防止定义的action-type的常量重复?
- 12. CDN的特点及意义?
- 13. 为什么for循环比forEach性能高?
- 14. 说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
- 15. React render方法的原理,在什么时候会触发?
- 16. ![] == ![],![] == [],结果是什么?为什么?
- 17. 什么是闭包,应用场景是什么?
- 18. 谈谈你是如何做移动端适配的?
- 19. 移动端1像素的解决方案?
- 20. 弹性盒中的缩放机制是怎样的?
前端面试题
1. props和state相同点和不同点?render方法在哪些情况下会执行?
props:
props是一个从外部传进组件的参数,由于React具有单向数据流的特性,所以他的主要作用是从父组件向子组件中传递数据,它是不可改变的,如果想要改变它,只能通过外部组件传入新的props来重新渲染子组件,否则子组件的props和展示形式不会改变,props除了可以传字符串,数字,还可以传递对象,数组甚至是回调函数。
state:
state主要作用是用于组件保存,控制及修改自己的状态,它只能在constructor中初始化,state是可以被改变的,state放改动的一些属性,比如点击选中,再点击取消,类似这种属性就放入带state中,
注意:没有state的叫做无状态组件,多用props少用state,多写无状态组件,注意:修改state的值时,必须通过调用setState方法,当我们调用this.setState方法时,React会更新组件的数据状态,并且重新调用render方法。
不同点:
- 1.props不可以在组件内部修改,但state可以在组件内部修改
- 2.可以从父组件修改自组件的props,而不能从父组件修改自组件的state。
相同点:
- 1.props和state都是导出HTML的原始数据。
- 2.props和state都是确定性的,如果我们写的组件为同一props和state的组合生成了不同的输出,那木我们肯定在哪里做错了
- 3.props和state都会触发渲染更新
- 4.props和state都是纯JS对象(用typeof来判断,结果都是object)
- 5.可以从父组件得到初始值props和state的初始值
render方法在哪些情况下会执行?
在类组件和函数组件中,render函数的形式是不同的。
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件。
在render函数中的jsx语句会被编译成我们熟悉的js代码
在render过程中,React 将新调用的 render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新 DOM树
触发机制:
类组件调用 setState 修改状态 函数组件通过useState hook修改状态。
函数组件通过useState这种形式更新数据,当数组的值不发生改变了,就不会触发render
总结:
render函数里面可以编写JSX,转化成createElement这种形式,用于生成虚拟DOM,最终转化成真实DOM
在React 中,类组件只要执行了 setState 方法,就一定会触发 render 函数执行,函数组件使用useState更改状态不一定导致重新render
组件的props 改变了,不一定触发 render 函数的执行,但是如果 props 的值来自于父组件或者祖先组件的 state
在这种情况下,父组件或者祖先组件的 state 发生了改变,就会导致子组件的重新渲染
所以,一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染
2. shouldComponentUpdate有什么作用?
shouldComponentUpdate询问组件是否需要更新的一个钩子函数,判断数据是否需要重新渲染,返回一个布尔值。默认的返回值是true,需要重新render()。若如果返回值是false则不触发渲染,利用这个生命周期函数可以强制关闭不需要更新的子组件来提升渲染性能。 这个方法用来判断是否需要调用 render 方法重新描绘 dom。 因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。
3. 说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?
本题详解:https://blog.csdn.net/beifeng11996/article/details/127489690
虚拟dom的理解 实际上它只是一层对真实DOM的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上 创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应
虚拟dom的实现原理 React虚拟DOM的实现原理,通过JS模拟网页文档节点,生成JS对象树(虚拟DOM),然后再进一步生成真实的DOM树,再绘制到屏幕。如果后面有内容发生改变,React会重新生成一棵全新的虚拟DOM树,再与前面的虚拟DOM树进行比对diff,把差异的部分打包成patch,再应用到真实DOM,然后渲染到屏幕浏览器。
diff .React需要同时维护两棵虚拟DOM树:一棵表示当前的DOM结构,另一棵在React状态变更将要重新渲染时生成。React通过比较这两棵树的差异,决定是否需要修改DOM结构,以及如何修改。这种算法称作Diff算法。
key 当同一层级的某个节点添加了对于其他同级节点唯一的key属性,当它在当前层级的位置发生了变化后。react diff算法通过新旧节点比较后,如果发现了key值相同的新旧节点,就会执行移动操作(然后依然按原策略深入节点内部的差异对比更新),而不会执行原策略的删除旧节点,创建新节点的操作。这无疑大大提高了React性能和渲染效率
实则用到了diff算法中的element 层对比,详情可见: https://blog.csdn.net/m0_53644435/article/details/123440036
4. react新出来两个钩子函数是什么?和删掉的will系列有什么区别?
React16废弃的生命周期有3个will:
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
废弃的原因: 是在React16
的Fiber
架构中,调和过程会多次执行will周期,不再是一次执行,失去了原有的意义。此外,多次执行,在周期中如果有setState
或dom
操作,会触发多次重绘,影响性能,也会导致数据错乱。
React16的2个新的生命周期:
- getDerivedStateFromProps
- getSnapshotBeforeUpdate
getDerivedStateFromProps的用法:
触发时机频繁,16.3是在props变化时触发,16.4则改为在每次组件渲染器调用,即无论props变化,组件自己setState,父组件render 都会触发 静态方法,本意是隔离访问组件实例,却造成访问组件的数据和方法十分不便,难以进行数据比较 不能setState,而是返回一个对象来更新state,使用不便,也可能触发多次更新状态 当组件实例化的时候,这个方法替代了componentWillMount(),而当接收到新的 props 时,该方法替代了 componentWillReceiveProps() 和 componentWillUpdate()
getSnapshotBeforeUpdate的用法:
在render之后,更新dom之前,state已更新。可以用来读取dom,强制用户只能在mount阶段读取dom。 getSnapshotBeforeUpdate这个周期在Fiber架构中,只会调用一次。
5. React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历?
在reactJS 中 props.children 不一定是数组, 有三种可能 :
- 1、当前组件没有子节点数据类型就是undefined,
- 2、有一个子节点数据类型就是object 。
- 3、 有多个子节点的时候才会是array ,只有在多个节点的时候才可以直接调用map方法,
react资深提供了一个react.children.map()方法,可以安全遍历子节点对象。
系统提供React.Children.map()方法安全的遍历子节点对象
6. React组件之间如何通信?
1、父传子:
⽗组件可以通过向⼦组件传 props 的⽅式来实现
2、子传父:
可以采用props+回调的方式
3、兄弟组件通信:
可以通过兄弟节点的共同父节点,由父节点转发信息,实现兄弟间通信
4、跨层级通信:
使用context状态树
5、发布者订阅者模式:
发布者发布事件,订阅者监听到事件后做出反应,可以通过引⼊ event 模块进⾏
6、全局状态管理工具:
可以借助 Redux 或 Mobx以及react-redux 等全局状态管理⼯具进⾏通信,它们会维护⼀个全局状态中⼼(Store),并可以根据不同的事件产⽣新的状态 hooks中帮我们封装好的:useContext和useReducer
7. 谈谈你对immutable.js的理解?
Immutable,不可改变的,在计算机中,即指一旦创建,就不能再被更改的数据
对 Immutable对象的任何修改或添加删除操作都会返回一个新的 Immutable对象
Immutable 实现的原理是 Persistent Data Structure(持久化数据结构):
用一种数据结构来保存数据 当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会对内存造成浪费 也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免 deepCopy把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享)
如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享
8. redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?
详情: linkhttps://www.cnblogs.com/houjl/p/10165498.html
9. redux中同步action与异步action最大的区别是什么?
同步action:
执行了dispatch函数之后,对应的reducer纯函数立即得到执行,reducer执行完了之后,state立即就改变了,此时用store.getState函数,取到的是最新的state值;
异步action:
原则上redux并没有提供异步action的处理方案,异步的action需要依赖第三方的中间件解决(如redux-thunk),dispatch了一个异步action(本质上是dispatch的一个函数)之后,目标state并不会立即响应,而是要看异步函数内部的逻辑,来决定state什么时候响应.
10. redux-saga和redux-thunk的区别与使用场景?
详情: https://blog.csdn.net/qq_43403486/article/details/120340876
11. 在使用redux过程中,如何防止定义的action-type的常量重复?
ES6引入了一种新的原始数据类型Symbol
,表示独一无二的值。 Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象 Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
12. CDN的特点及意义?
什么是CDN?
CDN 意为内容分发网络,是基于现有网络的智能虚拟网络,分布在世界各地的边缘服务器上。基本思路是避免互联网上可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输更快更稳定。
CDN 表示将数据从原始服务器复制到其他服务器。当用户访问时,他们可以在复制了数据内容的服务器上进行访问。其目的是使用户能够更快更好地获取所需内容,解决网络拥塞情况,提高用户访问网站的响应速度。CDN 加速成本低,速度快,适合访问量比较大的网站。
CDN 具有以下主要功能 :
- 1.节省骨干网带宽,降低带宽需求;
- 2.提供服务器端加速,解决大量用户访问导致的服务器过载问题;
- 3.服务提供商可以利用Web Cache技术将用户访问的网页和对象缓存在本地,这样对相同对象的访问就不需要占用骨干网的出口带宽,相应的用户访问网页的时间要求也增加了;
- 4.可以克服网站分布不均的问题,降低网站自身的建设和维护成本;
- 5.减少“通信风暴”的影响,提高网络访问的稳定性。
CDN 的特点:
- 1.本地缓存加速:提高了企业网站(尤其是包含大量图片和静态页面的网站)的访问速度,大大提高了上述网站的稳定性。
- 2.镜像服务:消除了不同运营商之间互联瓶颈带来的影响,实现了跨运营商的网络加速,保证了不同网络的用户都能获得良好的接入质量。
- 3.远程加速:远程访问用户根据DNS负载均衡技术智能自动选择缓存服务器,选择最快的缓存服务器加速远程访问。
- 4.带宽优化:自动生成服务器的远程镜像缓存服务器。远程用户访问时,可以从缓存服务器读取数据,减少远程访问的带宽,分担网络流量,减轻原WEB服务器的负载。
- 5.集群抗攻击:广泛分布的CDN 节点加上节点间的智能冗余机制,可以有效防止黑客入侵,降低各种D.D.o.S攻击对网站的影响,同时保证更好的服务质量。
13. 为什么for循环比forEach性能高?
for( )循环:
通过下标,对循环中的代码反复执行,功能强大,可以通过index取得元素。在处理比较复杂的处理的时候较为方便
forEach( )循环:
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。foreach有的也叫增强for循环,foreach其实是for循环的一个特殊简化版。注意,forEach() 对于空数组是不会执行回调函数的
for和forEach的区别:
1、遍历:
for循环按顺序遍历,forEach使用iterator迭代器遍历
2、数据结构:
for循环是随机访问元素,foreach是顺序链表访问元素
3、性能上:
对于arraylist,是顺序表,使用for循环可以顺序访问,速度较快;使用foreach会比for循环稍慢一些。 对于linkedlist,是单链表,使用for循环每次都要从第一个元素读取next域来读取,速度非常慢;使用foreach可以直接读取当前结点,数据较快;
如何选择:
foreach相对于for循环,代码减少了,但是foreach依赖IEnumerable。在运行的时候效率低于for循环。当然了,在处理不确定循环次数的循环,或者循环次数需要计算的情况下。使用foreach比较方便。而且foreach的代码经过编译系统的代码优化后,和for循环的循环类似。
可以说,foreach语句是for语句的特殊简化版本,在遍历数组、集合方面,foreach为开发人员提供了极大的方便。在复杂的循环设计时,还是应该使用for循环更加的灵活。
14. 说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
reduxjs/toolkit:
Redux
官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式,使用 Redux Toolkit
都可以优化你的代码,使其更可维护
react-redux:
react官方推出的redux绑定库
,react-redux
将所有组件分为两大类:
UI组件和容器组件,其中所有容器组件包裹着UI组件,构成父子关系。容器组件负责和redux交互,里面使用redux API函数,UI组件负责页面渲染,不使用任何redux API。容器组件会给UI组件传递redux中保存对的状态和操作状态的方法
15. React render方法的原理,在什么时候会触发?
在类组件和函数组件中,render函数的形式是不同的。
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件。
在render函数中的jsx语句会被编译成我们熟悉的js代码
在render过程中,React 将新调用的 render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新 DOM树
触发机制:
类组件调用 setState 修改状态 函数组件通过useState hook修改状态。函数组件通过useState这种形式更新数据,当数组的值不发生改变了,就不会触发render
总结:
render函数里面可以编写JSX,转化成createElement这种形式,用于生成虚拟DOM,最终转化成真实DOM
在React 中,类组件只要执行了 setState 方法,就一定会触发 render 函数执行,函数组件使用useState更改状态不一定导致重新render
组件的props 改变了,不一定触发 render 函数的执行,但是如果 props 的值来自于父组件或者祖先组件的 state
在这种情况下,父组件或者祖先组件的 state 发生了改变,就会导致子组件的重新渲染
所以,一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染
16. ![] == ![],![] == [],结果是什么?为什么?
1、根据运算符优先级 ,! 的优先级是大于 == 的,所以先会执行 ![]
!可将变量转换成boolean类型,null、undefined、NaN以及空字符串(‘’)取反都为true,其余都为false。
所以 ! [] 运算后的结果就是 false
也就是 [] == ! [] 相当于 [] == false
2、根据上面提到的规则(如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false转换为0,而true转换为1),则需要把 false 转成 0
也就是 [] == ! [] 相当于 [] == false 相当于 [] == 0
3、根据上面提到的规则(如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较,如果对象没有valueOf()方法,则调用 toString())
而对于空数组,[].toString() -> ‘’ (返回的是空字符串)
也就是 [] == 0 相当于 ‘’ == 0
4、根据上面提到的规则(如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值)
Number(‘’) -> 返回的是 0
相当于 0 == 0 自然就返回 true了
17. 什么是闭包,应用场景是什么?
什么是闭包 闭包就是一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)
也就是说 闭包可以让你在一个内层函数中访问到其外层函数的作用域 , 也可以说是函数 + 上下文调用
在 JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁
应用场景:
任何闭包的使用场景都离不开这两点:
- 1、创建私有变量
- 2、延长变量的生命周期
注意点:
如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响
18. 谈谈你是如何做移动端适配的?
详情: https://blog.csdn.net/weixin_44602430/article/details/120909358
19. 移动端1像素的解决方案?
为什么会有一像素问题 在移动端分辨率是不相同的,目前来说可以分一倍屏,二倍屏,三倍屏,在不同分辨率上显示的1像素可能会被渲染为2个像素点或者三个像素点,这样严重影响了美观,所以我们要解决一像素问题
解决方案: https://blog.csdn.net/Qian_mos/article/details/88945352
20. 弹性盒中的缩放机制是怎样的?
弹性盒中的项目设置flex-grow属性定义项目的放大比例,默认值为0,值越大,放大越厉害,且不支持负值;
而flex-shrink属性定义项目的缩小比例,默认值为1,数值越大,缩小越厉害,同样不支持负值;
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间,浏览器根据这个属性,计算主轴是否有多余空间。他的默认值为auto,也就是项目的本来大小。
注意:它可以设为跟width或height属性一样的值,比如给具体的像素值,则项目将占据固定空间。