前端面试题 react篇

1.说说你对react的理解?有哪些特性

 React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案 遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效 使用虚拟 DOM 来有效地操作 DOM,遵循从高阶组件到低阶组件的单向数据流 帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面

特性:函数式编程 jsx语法 组件化开发模式 虚拟dom 单项数据绑定

2.说说Real diff算法是怎么运作的?

Diff算法是为了节省性能而设计的,diff算法和虚拟dom的结合。


基本流程:在第一次render在执行的时候会将第一次的虚拟DOM做依次缓存,当第二次渲染时会将新的虚拟DOM和旧的虚拟DOM进行比较,计算出虚拟DOM中真正发生变化的部分,从而值针对变化的部分进行更新渲染,避免造成性能的浪费 
 

3.说说React生命周期有哪些不同的阶段?每个阶段对应的方法是? 

挂载阶段:

constructor():在react组件挂载之前,会调用它的构造函数
ComponentWillMount():在render()方法之前调用,并且在初始化挂载及后续更新时都会被调用
ComponentDidMount():在挂载之后(插入dom树中)立即调用
更新阶段:

componentWillReceiveProps():在接收父组件改变后的props需要重新渲染组件时使用的比较多,外部组件频繁的时候会导致效率会比较低
ShouldComponentUpdate():用于控制组件重新渲染的流程,在这return false 可以阻止组件的更新
Render():render()方法是class组件当中唯一必须实现的方法
ComponentWillUpdate():ShouldComponentUpdate()返回true后,组件进入重新渲染之前进入这个函数
ComponentDidUpdate():每次改变state重新渲染页面后都会进入到这个生命周期
卸载销毁阶段

ComponentWillUnmount():在此完成组件的卸载和数据的销毁

4. 说说你对React中虚拟dom的理解?


虚拟dom不会进行排版和重绘的操作,我们使用虚拟dom来减少对真实dom的操作,可以达到使用虚拟dom提高性能,但是在首屏需要加载大量的dom时使用虚拟dom就会比不使用虚拟dom的速度要慢,因为虚拟dom会对真实dom进行一次对比

5.说说你对react hook的理解?


可以使用hooks从组件中提取状态逻辑,让这些逻辑可以单独测试并且hooks使我们在无需修改组件结构的情况下复用状态逻辑,hooks将组件中互相关联的部分拆解成更小的函数,还可以使用reducer来管理组件内部状态让其更可预测,hooks让我们在非class组件的情况下使用更多的react的特性

6.React组件之间如何通信?


组件之间的通信分为父传子通信,子传父通信,非父子组件通信

父传子:在父组件中的子组件标签上绑定自定义属性,挂载传递的数据
子组件中props接收传递过来的数据,直接使用即可

子传父:父组件中子组件标签上绑定一个属性,传递一个方法给子组件
子组件中通过props接收这个方法,直接调用,传递相应的参数就可以

非父子组件的通信:状态提升(中间人模式),context状态树

状态提升:react中的状态提升就是将多个组件需要共享的状态提升到他们最近的父组件当中,在父组件上改变这个状态然后通过props发给子组件
Context状态树:在父组件中我们通过createContext()创建一个空对象,在父组件的最外层我们使用Provider包裹数据,通过value绑定要传递的对象数据


7.说说你对受控组件和非受控组件的理解?应用场景?


受控组件:由react控制的输入表单元素而改变其值的方式叫做受控组件
应用场景:比如表单元素input绑定一个onChange事件,当input状态发生变化时就会触发onChange事件,从而更新组件state

非受控组件:非受控组件就是指,表单数据由DOM本身处理,即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示最新值,在非受控组件中,可以使用ref来从DOM获取表单值
应用场景:在输入框显示用户输入数据,并不更新state,在使用ref获取表单值是更新state

8.说说Connect组件的原理是什么?


connect有四个参数(两个不常用)

第一个:是mapStateToProps这个函数允许我们将store中的数据作为props绑定到数组上,主要原理就是将需要绑定的props作为一个函数传过来,在connect中传递给mapStateToProps一个真实的store数据
第二个:是mapDispatchToProps由于更改数据必须要触发action,因此在这个参数的主要功能就是将action作为props绑定到组件上
执行流程

connect是一个高阶函数,首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入wrapWithConnect,这样就生产出一个经过包裹的Connect组件
通过props.store获取祖先Component的store
props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component
componentDidMount时,添加事件
this.store.subscribe(this.handleChange),实现页面交互
shouldComponentUpdate时判断是否有避免进行渲染
提升页面性能,并得到nextState
componentWillUnmount时移除注册的事件this.handleChange


9.说说react 中jsx语法糖的本质?


Jsx是JavaScript的语法扩展,或者说是一个类似xml的ECMAScript的语法扩展,它本身没有太多的语法定义,也不期望引入更多的标准

React并不强制使用jsx,jsx通过类似xml的描述方式,描写函数对象,即使在使用了jsx也会在构建过程中,通过babel转换成createElement,所以jsx更像是react的语法糖

10.说说你对redux中间件的理解?常用的中间件有哪些?实现原理?


理解
Redux中,中间件就是放在dispatch过程,在分发action进行拦截处理,redux的整个工作流程是,当action发出后reducer立即算出state,整个过程是一个同步的操作,那如果需要支持异步操作,或者支持错误处理,日志监控,这个过程就可以加上中间件,他的一个本质就是一个函数对store.dispatch方法进行了改造,在发出action和执行reducer这两步之间,添加了其他的功能
常用的中间件有:redux-thuck:用于异步操作、redux-logger:用于日志记录
实现原理:中间件都需要通过applyMiddleWares进行注册,作用就是将所有的中间件组成一个数组,依次执行然后作为第二个参数传入create Store中


11.说说AMD、CMD、commonJS模块化规范的区别?


AMD规范就是非同步加载模块,允许指定回调函数,对于依赖的模块AMD是提前执行,requirejs是AMD推崇依赖前置,AMD的api默认是一个当多个用
CMD:对于依赖的模块是延迟执行,CMD严格的区分api
CommonJS用同步的方式加载模块。在服务端,模块文件都存放在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。

12.说说package.json中版本号的规则?


软件版本号有四部分组成:

第一部分为主版本号,变化了表示有了一个不兼容上个版本的大更改。
第二部分为次版本号,变化了表示增加了新功能,并且可以向后兼容。
第三部分为修订版本号,变化了表示有bug修复,并且可以向后兼容。
第四部分为日期版本号加希腊字母版本号,希腊字母版本号共有五种,分别为base、alpha、beta 、RC 、 release


13.说说React jsx转换成真实DOM的过程?


使用react.createElement或者是JSX编写的react组件,实际上所有的jsx代码都会转换成react.createElement的内容,babel帮助我们完成了转换的过程,createElement函数对key和ref等特殊的props进行处理,并会获取defaultProps对默认props进行赋值,并且对传入的子节点进行处理,最终构造成一个虚拟dom对象

14.说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?


@reduxjs/toolkit是redux官方强烈推荐的一个高效的redux的开发工具集,他的宗旨在称为标准的redux逻辑开发模式redux toolkit最初就是为了帮我们解决现有redux的常见的三个问题而创建的;
由于配置redux store 过于复杂,我们必须添加有关的redux的很多软件包,才可以使用redux

区别
react-redux
react-redux 是的官方 React UI 绑定层,允许您的 React 组件从 Redux 存储中读取数据,并将操作分派到存储以更新状态。

@reduxjs/toolkit
@reduxjs/toolkit 是对 Redux 的二次封装,开箱即用可的一个高效的 Redux 开发工具集,使得创建store、更新store更加方便

15.React render方法的原理,在什么时候会触发?


render函数里面可以编写jsx,转化成createElement这种形式,用于生成虚拟dom,最终转换成真实dom,在react中,类组件只要执行了setState方法就一定会触发render函数的执行,函数组件使用useState更改状态不一定导致重新的render组件的props,改变了也不一定触发render函数的执行,但是如果props的值来自于父组件的state在这种情况下,父组件state发生了改变,就会导致子组件的重新渲染,所以一旦指令setState就会执行render,useState会判断当前值有没有发生改变,确定是否去执行render方法,一旦父组件发生渲染,子组件也会发生渲染

16.React性能优化的手段有哪些?


避免使用内联函数;事件的绑定方式;懒加载组件;服务器端渲染;数据的重复使用;组件的复用;
使用React.Memo来缓存组件、使用useMemo缓存大量的计算、使用React.PureComponent , shouldComponentUpdate、避免使用内联对象、避免使用匿名函数、延迟加载不是立即需要的组件、调整CSS而不是强制组件加载和卸载、使用React.Fragment避免添加额外的DOM

17.如何通过原生js实现一个节流函数和防抖函数?


        防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。       如果n秒内高频事件再次被触发,则重新计算时间。

  • 节流:指定时间间隔内只会执行一次任务。

18.说说你对koa中洋葱模型的理解?

在 koa 中,中间件被 next() 方法分成了两部分。next() 方法上面部分会先执行,下面部门会在后续中间件执行全部结束之后再执行
在洋葱模型中,每一层相当于一个中间件,用来处理特定的功能,比如错误处理、Session 处理等等。其处理顺序先是 next() 前请求(Request,从外层到内层)然后执行 next() 函数,最后是 next() 后响应(Response,从内层到外层),也就是说每一个中间件都有两次处理时机。

总结

  • Koa 的洋葱模型指的是以 next() 函数为分割点,先由外到内执行 Request 的逻辑,再由内到外执行 Response 的逻辑。通过洋葱模型,将多个中间件之间通信等变得更加可行和简单。其实现的原理并不是很复杂,主要是 compose 方法。

19.说说如何借助webpack来优化前端性能?


webpack是一个模块打包工具,可以使用webpack管理模块,并分析模块间的依赖关系最终编译输出模块为html、JavaScript和css以及各种静态文件,让开发更加高效

通过webpack优化前端的手段有:
JS代码压缩、CSS代码压缩、Html文件代码压缩、文件大小压缩、图片压缩、Tree Shaking、代码分离、内联 chunk

20.说说你对webSocket的理解?


WebSocket,是一种网络传输协议,位于OSI模型的应用层。可在单个TCP连接上进行全双工通信,能更好的节省服务器资源和带宽并达到实时通迅

客户端和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输

而在websocket出现之前,开发实时web应用的方式为轮询,不停地向服务器发送 HTTP 请求,问有没有数据,有数据的话服务器就用响应报文回应。如果轮询的频率比较高,那么就可以近似地实现“实时通信”的效果;轮询的缺点也很明显,反复发送无效查询请求耗费了大量的带宽和 CPU资源

webSocket优点
较少的控制开销:数据包头部协议较小,不同于http每次请求需要携带完整的头部
更强的实时性:相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少
保持创连接状态:创建通信后,可省略状态信息,不同于HTTP每次请求需要携带身份验证
更好的二进制支持:定义了二进制帧,更好处理二进制内容
支持扩展:用户可以扩展websocket协议、实现部分自定义的子协议
更好的压缩效果:Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率

应用场景
基于websocket的事实通信的特点,其存在的应用场景大概有:

弹幕
媒体聊天
协同编辑
基于位置的应用
体育实况更新
股票基金报价实时更新
 

21.移动端1像素的解决方案

  1. 伪类+transform

  2. viewport + rem

  3. border-image

  4. background-image

  5. postcss-write-svg

22.弹性盒子的缩放机制是怎么样的?

弹性盒中的项目设置flex-grow属性定义项目的放大比例,默认值为0,值越大,放大越厉害,且不支持负值; 而flex-shrink属性定义项目的缩小比例,默认值为1,数值越大,缩小越厉害,同样不支持负值;

23.说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?

key 当同一层级的某个节点添加了对于其他同级节点唯一的key属性,当它在当前层级的位置发生了变化后。react diff算法通过新旧节点比较后,如果发现了key值相同的新旧节点,就会执行移动操作(然后依然按原策略深入节点内部的差异对比更新),而不会执行原策略的删除旧节点,创建新节点的操作

24.react新出来两个钩子函数是什么?和删掉的will系列有什么区别?

        新生命周期中新增了两个钩子,分别为getDerivedStateFromProps(从props中得到衍生的state)和getSnapshotBeforeUpdate

区别

1、componentWillMount中可能需要做的事(一些数据初始化的操作就应该放在这个钩子中处理),constructor与componentDidMount也能做,甚至做的更好,此方法被废弃。

2、componentWillReceiveProps实际行为与命名并不相符,由于不稳定性已由getDerivedStateFromProps代替;

3、而componentWillUpdate同等理由被getSnapshotBeforeUpdate代替

25.redux中同步action与异步action最大的区别是什么?

Redux中同步(synchronous)action和异步(asynchronous)action最大的区别在于它们被处理的方式。

同步action会直接触发一个纯函数reducer,并且这个reducer会返回一个新的状态对象。这个过程是同步进行的,因为执行完毕后应用程序立即访问新状态并更新UI。同步action通常用于改变应用程序中的一些小数据,比如用户输入、按钮单击等。

异步action与同步action有所不同,当我们需要在action处理期间执行异步逻辑的时候,我们需要使用异步action。这种情况下,我们将异步代码放在一个异步操作函数中,并通过middleware来派发异步操作。异步操作可能需要几秒钟或更长时间才能完成,但是在此之前,reducer不会收到任何新状态,因为它等待接收由异步action处理后的响应。一旦异步响应返回,middleware会将创建action的工作代理给redux,并将结果传递给对应的reducer,从而更新应用程序的状态并重新渲染UI。

总体来说,同步action和异步action都是Redux中重要的概念,以帮助管理应用程序状态的流动。但是它们的处理方式有所不同,开发人员需要根据具体情况来选择合适的方法来处理应用程序状态的管理。

26.redux-saga和redux-thunk的区别和应用场景?

Redux-saga和Redux-thunk是用于处理副作用(异步代码)的库,它们都可以被用在React/Redux应用程序中。两者在处理异步请求时有相似之处,但在实现方法和功能上存在区别。

Redux-thunk是Redux的中间件之一,它允许我们使用函数来代替对象来派发action。这些函数可以在派发action之前执行异步操作,并在操作完成后再派发action。通常情况下,Redux-thunk被用于处理简单的异步逻辑,如简单的API请求等。在实现上,其基本思想是将一个函数插入到Action和Reducer之间,通过这个函数返回一个Promise,当异步操作完成时,将可对状态树进行修改的新Action派遣到Reducer中。然而,Thunk具有遗留行为问题,并且需要将许多工作放在开发者的肩膀上,包括捕获错误、编写异步等待逻辑等。

相比之下,redux-saga提供了更强大的功能,并且可以简化处理更复杂的异步场景,如长轮询、WebSocket连接以及取消异步操作等操作。Redux-saga通过将异步操作看作是Yieldable的Generators,在Saga中结构化管理异步流程和SideEffects。Redux-saga使得异步流程层次化、可维护性高且具有可测试性等特点,将副作用承担到了saga自身而不是其他的业务组件。这使得应用程序也更具有可重复性、可预测性和容错性等特点。

27.在使用rdeux中如何防止定义的action-type的常量重复?

新建一个专门存放action-type常量的文件,例如constants.js或者ActionTypes.js,然后将所有的常量都以变量的形式在这个文件内定义。这样,在其他组件或者文件中使用这些常量时,直接引入该文件即可,避免了手写字符串而导致的拼写错误或者重复。

可以使用类似于"redux-actions"这样的第三方库来简化Redux中定义action的过程。该库提供了一个createActions()的方法,通过传入普通对象或者集合对象的方式,自动构建出相应的action-creator和action-type常量。通过该库创建出的action-type常量是不会重复的,并且易于维护。

28.说说你对@reduxjs/toolkit的理解?和react-redux有什么区别

@reduxjs/toolkit是一个Redux官方提供的工具集合,以帮助简化使用Redux的开发流程,并且提高开发效率。该工具集合包含了几个快捷函数和简化了的Redux配置,以及可提高性能和实现缓存Transforms等功能。

具体来说,@reduxjs/toolkit提供以下几个主要的功能:

  1. createSlice:这可以自动生成常规的action创建器以及reducer,有效地降低了手写代码的量。
  2. configureStore:这个函数使得我们可以集中管理应用程序状态,同时还可以方便地添加Middlewares或DevTools。
  3. createAsyncThunk:此功能提供了一种简单的方法,让我们将异步操作捆绑到Redux中,并为我们处理加载、错误和空闲状态。
  4. createSelector:通过创建Memoized Selector减少reselect库代码,以便我们在必要时手动优化性能。

相比之下,react-redux是与Redux集成的库,它允许我们通过connect函数将React组件连接到Redux存储,并从存储中获取和更新状态。React-Redux使应用程序的构建更加简单,更易于管理React组件与Redux数据间的通信。在某些情况下,它还提供了针对性能优化和开发流程自动化的附加功能,如shouldComponentUpdate和Redux DevTools等。

关键区别在于,@reduxjs/toolkit的目标是简化Redux开发流程,从而提高开发效率。它虽然可能不会为您处理所有东西,但是它可以减少您编写的代码量。React-Redux的主要目标是使React组件与Redux存储之间的沟通更加简单和可维护。

传统上,Redux需要开发人员编写许多重复、冗长和易出错的代码。使用@reduxjs/toolkit,我们只需要更少的代码就能完成相同的任务,同时也能够避免一些常见的错误。因此,@reduxjs/toolkit使得Redux应用程序的开发变得更为快速和简单了

你可能感兴趣的:(前端,react.js,javascript)