1.说说你对react的理解?有哪些特性?
React就是一个简单的javascript UI库,它用于构建高效快速的用户界面,,它是一个轻量级库,所以很受欢迎,它遵循组件编程模式,函数式编程范式,以使前端应用程序更加高效它使用虚拟dom来有效的操作
dom特性:
-
- 单向数据绑定
- 虚拟 DOM
- 声明式编程
- Component
- JSX 语法
优点:高效灵活、轻量级库、声明式的设计、简单使用、组件式开发、提高代码复用率
2.说说Real DOM和Virtual DOM的区别?优缺点
区别:
虚拟 DOM 不会进行排版与重绘操作,而真实 DOM 会频繁重排与重绘
虚拟 DOM 的总损耗是“虚拟 DOM 增删改+真实 DOM 差异增删改+排版与重绘”,真实 DOM 的总损耗是“真实 DOM 完全增删改+排版与重绘”
真实 DOM 的优势:易用
缺点:
效率低,解析速度慢,内存占用量过高
性能差:频繁操作真实 DOM,易于导致重绘与回流
使用虚拟 DOM 的优势如下:
简单方便:如果使用手动操作真实 DOM 来完成页面,繁琐又容易出错,在大规模应用下维护起来也很困难
性能方面:使用 Virtual DOM,能够有效避免真实 DOM 数频繁更新,减少多次引起重绘与回流,提高性能
跨平台:React 借助虚拟 DOM,带来了跨平台的能力,一套代码多端运行
缺点:
在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化
首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,速度比正常稍慢
3.说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?
创建阶段:constrctor:初始化的时候执行
getsnapshouldbeforupdate:在render执行前初始化后执行
Render
ComponentDidMount:在render执行后执行
挂载阶段:getsnapshouldbeforupdate
Shouldcomponentupdate:通过返回值来控制render
Render
CompoenntDidUpdate:挂载runder之后执行
销毁阶段:
componentWillDidMount:销毁残留变量,日志等等
4.说说React中setState执行机制
1.setState是异步的
1 .调用setState是不会立即更新的
2 .所有组件使用的是同一套更新机制,当所有组件didmount之后,父组件didmount,然后统一执行更新
3 .更新时会把每个组件的更新合并,每个组件只会触发一次更新后的生命周期
2.异步函数和原生事件中的setState
1 .用setTimeout模拟异步和回调接口执行情况
2 .在这种情况下,setState会同步更新的
5.说说react的事件机制
React
基于浏览器的事件机制自身实现了一套事件机制,包括事件注册、事件的合成、事件冒泡、事件派发等
在React
中这套事件机制被称之为合成事件
合成事件是 React
模拟原生 DOM
事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器,根据 W3C
规范来定义合成事件,兼容所有浏览器,拥有与浏览器原生事件相同的接口
执行顺序
React 所有事件都挂载在 document 对象上
当真实 DOM 元素触发事件,会冒泡到 document 对象后,再处理 React 事件
所以会先执行原生事件,然后处理 React 事件
最后真正执行 document 上挂载的事件
6.React组件之间如何通信
父子组件通信:
父组件向子组件通信:在父组件的子组件标签上绑定一个参数将要传递的值放在这里,然后通过props传递给子组件,子组件可以通过this.props来接收参数
子组件向父组件通信:在父组件的子组件标签上绑定一个方法,通过props传递给子组件,子组件使用this.props接收这个方法,并且调用,将想要传递的参数放在方法内,然后父组件调用这个方法就可以接收到
兄弟组件通信:
在兄弟组件的共同父组件的子组件两个标签上绑定参数,跟子传父的方法相同,只不过父组件将接受来的两个子组件的数据分别给对方兄弟发送过去,实现兄弟组件通信
Context传值:
因为使用props传值会有限制,必须是兄弟组件或者父子组件才可以,不能够跨组件传值,而context则可以跨组件传值。首先在组件中创建一个context对象,然后在context标签上调用provider,在绑定一个value值,接下来在传值的组件中接收这个context标签,然后调用这个标签,这时候接收的value就可以获取到其它组件传入标签的值了
7.说说你对受控组件和非受控组件的理解?应用场景?
受控组件
就是受到控制的组件,比如说类组件,存放数据要统一放在状态state中,具有唯一的数据源,如果存放在其它地方则无法进行调用操作,而想要修改状态中的值,只能通过setstate来进行修改,由于异步的问题在修改state后无法打印获取,所以需要用到setstate的第二个参数:回调函数,在回调函数内部打印状态,可以实时获取到state的最新值
非受控组件
就是不受到控制的组件:这类组件不讲数据保存在状态中,没有唯一的数据源,通常使用ref,或者event来获取值保存值,例如函数组件,数据可以保存在自己声明的变量中,也可以保存在hooks:useState中
应用场景:
受控组件:类组件
非受控组件:函数组件
8.说说你对fiber架构的理解?解决了什么问题
Fiber架构是对react算法的一次重新实现
它给任务增加了优先级,在线程中先执行优先级高的任务,优先级低的则会被中断,等优先级高的任务执行完毕后,在重新去执行被中断的热任务
它给任务添加了异步,调用requestdelcallback api,在浏览器空闲的时候执行
为每一个任务增加了线程,一个线程对应一个任务,对应两个链表,
减少了浏览器一次性执行大量的dom操作,给用户增加了体验感,增加了游览器的执行效率
从架构角度来看,Fiber
是对 React
核心算法(即调和过程)的重写
从编码角度来看,Fiber
是 React
内部所定义的一种数据结构,它是 Fiber
树结构的节点单位,也就是 React 16
新架构下的虚拟DOM
9.说说react diff的原理是什么
Diff就是react的算法的实现
通过比较新旧的虚拟dom,来找出dom节点数据的变化之处,然后根据变化指出实现针对性渲染
在react中diff算法是从上到下执行的
Diff算法遵循了三个层阶:
Tree层:比对tree树的节点,只会比对同一层的节点,不支持跨层级
Component层:比对两个组件,先判断两个组件的类型是否相同,如果不同则直接删除重新创建
Element层:比对两个节点,通过比对节点的唯一性指标key值,来判断否是需要删除创建。
10.说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
redux:
就是通过执行dispatch传递action向reducer发送需求,然后通过返回新的state修改状态
而redux中间件就是在dispatch发送action给reducer的过程中增加一些操作,比如说日志监控,异步任务等等。在发送后会先执行新加的中间件,等中间件执行完毕后,在执行发送来的action。
常用的中间件有:
Redux-logger:日志监控
Redux-thunk:异步操作
实现原理:
中间件都被放进了一个数组,然后嵌套执行,最后执行store.dispatch,中间件的内部可以拿到,getState和dispatch,内部会进行一个判断
11.如何使用css实现一个三角形,写出两种以上方案得满分
1.border:
使用 CSS 绘制三角形的第一种方法就是使用 border 属性。
给定一个宽度和高度都为 0 的元素,其 border 的任何值都会直接相交,我们可以利用这个交点来创建三角形。
2. linear-gradient
linear-gradient 需要结合 background-image 来实现三角形
3. clip-path
lip-path 就是使用长方形来绘制多边形(或圆形、椭圆形等)并将其定位在元素内
12.什么是强缓存和协商缓存?
强缓存是通过两个字段进行控制的,都是表示资源缓存的有效时间
协商缓存则是通过服务器来决定是否需要缓存,主要涉及到了两个属性字段,这两个属性字段都是成双成对出现的,在发送请求的时候会带上其中一个字段,则在后续请求的时候就将这个字段的对应字段带上,如果请求头上没有这个字段,则响应上也不会有
13.说说React jsx转换成真实DOM的过程?
react中的jsx语法会通过babel转化为 js代码,以React.createElement函数形式存在,createElement函数返回一个ReactElement函数,ReactElement函数返回一个的虚拟节点,虚拟节点中嵌套虚拟节点,就形成了虚拟DOM,最后通过ReactDOM.render方法转化为真实DOM
14.说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
react-redux
react官方推出的redux绑定库,react-redux将所有组件分为两大类:UI组件和容器组件,其中所有容器组件包裹着UI组件,构成父子关系。容器组件负责和redux交互,里面使用redux API函数,UI组件负责页面渲染,不使用任何redux API。容器组件会给UI组件传递redux中保存对的状态和操作状态的方法
@reduxjs/toolkit
Redux 官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式,使用 Redux Toolkit 都可以优化你的代码,使其更可维护
区别:
reduxjs/tookit相对于react-redux来说比较方便,集成了redux-devtools-extension,不需要额外的配置,非常方便
reduxjs/tookit集成immutable-js的功能,不需要安装配置使用,提升了开发效率
reduxjs/tookit集成了redux-thunk的功能
reduxjs/tookit将types、actions、reducers放在一起组成了全新的slices,简化了我们的使用
15.React render方法的原理,在什么时候会触发?
在类组件和函数组件中,render函数的形式是不同的。
在类组件中render函数指的就是render
方法;而在函数组件中,指的就是整个函数组件。在render函数中的jsx语句会被编译成我们熟悉的js代码
触发时机
render
的执行时机主要分成了两部分:
类组件调用 setState 修改状态
函数组件通过useState hook
修改状态
函数组件通过useState
这种形式更新数据,当数组的值不发生改变了,就不会触发render
16.React性能优化的手段有哪些?
避免使用内联样式,因为在重新渲染的时候,回重复创建
使用immutable:避免多次调用
使用fragment:避免被标记
使用懒加载:可以减少首次渲染的内存大小
使用防抖和节流:都可以避免多次点击造成了重复调用
使用usecallback和usememo:除非依赖发生变化,不然不会重新渲染页面
使用css动画替代js动画,因为css动画的内容和规则不会对页面造成损坏
17.如何通过原生js实现一个节流函数和防抖函数,写出核心代码,不是简单的思路
Function jl(fn,delay=500){
Let oldtime = Date.now()
Function bl(null,args){
Let newtime = Date.now()
If(newtime-oldtime > delay){
Fn.apply(...args)
Let oldtime = Date.now()
}
}
}
Function fd(fn,delay){
Let timer
Return Function (){
Let context = this
Let args = argument
Clearsettimeout(timer)
Timer = sertTimeout(()=>{
Fn.apply(context,args)
},delay)
}
}
18.说说webpack中代码分割如何实现
Webpack 实现代码分割的主要方法
使用动态导入语法(Dynamic Import Syntax)或者配置 optimization.splitChunks。
动态导入语法
Webpack 2 提供了 import() 函数来实现动态导入模块。这个函数会返回一个 Promise 对象,可以用于异步加载模块。在 Webpack 中,可以将动态导入语法用于实现代码分割
19.说说如何借助webpack来优化前端性能?
1.使用最新版本的 Webpack 和相关 Loader 和 Plugin,因为新版本的 Webpack 通常都会有优化和性能提升。
2.减少文件搜索范围,通过配置 resolve.modules、resolve.extensions、resolve.alias 等来减少 Webpack 查找文件的范围,减少构建时间。
3.使用 DllPlugin 和 DllReferencePlugin 来提前将第三方库打包好,避免重复打包,减少构建时间。
4.使用 HappyPack 将 Loader 转化为多进程模式,提高多核 CPU 的利用率,加快构建速度。
5.使用 webpack-parallel-uglify-plugin 或者 TerserWebpackPlugin 等插件对代码进行压缩,减小打包后的文件体积,提高加载速度。
6.开启 Webpack 的缓存机制,通过配置 cache-loader 或者 hard-source-webpack-plugin 来将构建结果缓存到本地,避免重复构建。
7.将开发时使用的依赖和生产环境使用的依赖分开打包,通过配置 splitChunks 来实现,避免将开发时不需要的依赖也打包进去。
8.移除不必要的 Loader 和 Plugin,只保留必要的 Loader 和 Plugin,避免 Webpack 做无用功。
9.避免在 Webpack 配置文件中进行耗时的操作,如避免在配置文件中使用复杂的计算、循环等操作。
20.说说javascript内存泄漏的几种情况?
-
闭包:内存中的值返回后会一直保存在内存中,会造成内存泄露
-
意外的全局变量:在函数中创建的变量没有声明,就会自动在全局中创建,会导致内存泄漏
-
定时器:创建的定时器如果在执行后没有被删除,内部的函数,变量没有回收,会造成内存泄漏
-
不要编写死循环的方法,会导致内存泄漏
-
反复重写一个属性会导致内存大量泄露
-
DOM对象和JS对象相互引用
-
给DOM对象添加的属性是另一个对象的引用
-
事件没有正确解绑
-
大量数据没有及时清理