前端面试题整理
- js面试题
- 1.SPA(单页应用)首屏加载速度慢怎么解决?
- 2.什么是强缓存和协商缓存?
- 3.说说 React 生命周期有哪些不同阶段?每个阶段对应的方法是?
- 4.什么是响应式设计?响应式设计的基本原理是什么?如何做?
- 5.说说webpack中常见的loader?解决了什么问题?
- 6.如何通过原生js实现一个节流函数和防抖函数?
- 7.说说你对koa中洋葱模型的理解?
- 8.说说你对webSocket的理解?
- 9.for...in循环和for...of循环的区别?
- 10.说说你对Object.defineProperty()的理解?
- React面试题
- 1.setState 是同步,还是异步的?
- 2.说说React Jsx转换成真实DOM过程?
- 3.state 和 props有什么区别?
- 4.react中懒加载的实现原理是什么?
- 5.说说你对react的理解?有哪些特性?
- 6. 说说Real DOM和Virtual DOM的区别?优缺点?
- 7.说说React中setState执行机制
- 8.说说react的事件机制?
- 9.说说你对fiber架构的理解?解决了什么问题?
- 10.说说React jsx转换成真实DOM的过程?
- 11.说说Real diff算法是怎么运作的?
- 12.说说你对react hook的理解?
- 13.React组件之间如何通信
- 14.说说你对受控组件和非受控组件的理解?应用场景?
- 15.说说react 中jsx语法糖的本质?
- 16.说说package.json中版本号的规则?
- 17.14.说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
- 18.React性能优化的手段有哪些?
- 19.调和阶段setState干了什么?
- 20.React合成事件的原理?
- 21.说说Connect组件的原理是什么?
- 22.说说你对fiber架构的理解?解决了什么问题?
- 23.前端跨域的解决方案(proxy)?
- Vue面试题
- 1.Vuex有几种属性,它们存在的意义分别是什么?
- Html面试题
- 1.从浏览器地址栏输入url到显示页面的步骤?
- Git
- 1.git rebase 和git merge的理解?区别?
js面试题
1.SPA(单页应用)首屏加载速度慢怎么解决?
一、什么是首屏加载
首屏时间(First Contentful Paint),指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容,首屏加载可以说是用户体验中最重要的环节。
二、加载慢的原因
在页面渲染的过程,导致加载速度慢的因素可能如下:
1.网络延时问题
2.资源文件体积是否过大
3.资源是否重复发送请求去加载了
4.加载脚本的时候,渲染内容堵塞了
三、解决方案
- 减小入口文件体积
- 静态资源本地缓存
- UI框架按需加载
- 图片资源的压缩
- 组件重复打包
- 开启GZip压缩
- 使用SSR
2.什么是强缓存和协商缓存?
1.什么是缓存
我们常说的缓存,缓存一般都是根据浏览器来说的,当我们第一次访问网站的时候,程序会把网站上的图片和数据会下载到电脑上,如果我们再次访问网站的时候,网站就会从本地直接加载出来,这就是缓存。
2.浏览器缓存是什么意思
浏览器缓存是为了节约资源,并且可以加速浏览网站的速度,当用户第一次进行访问网页的时候,浏览器在用户磁盘上对请求的文档进行保存,当用户第二次访问的时候,就会从本地直接显示,从而提高了访问页面的速度。
3.什么是强缓存
服务器通过设置http中hdader的Expires和cache-control字段告诉浏览器换存的有效期。这种方法会有一个固定时间,所带来的问题是如果服务器数据进行了更新,但是还没有到强缓存的过期时间,则数据无法更新。
4.Expires
Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
Expires的值是GMT格式的绝对时间,在设置的时间前浏览器会直接使用本地缓存。
5.cache-control
cache-control有12个值,其中的max-age值定义缓存的有效期,单位是秒,例如:cache-control:max-age=60,它表示缓存有效期为60秒,以消息的生成日期为基准,也就是header中的Date字段。
cache-control与Expires的区别在于cache-control的值是相对时间,而Expires是绝对时间,如果我们人为的修改了本地的时间,那么此时本地的时间与服务器上的时间不一致,就会导致缓存不能正确的被使用;而如果用相对时间,不管怎么改变本地的时间,缓存的有效期都不会改变。
6.什么是协商缓存
协商缓存就是通过服务器来判断缓存是否可用。
3.说说 React 生命周期有哪些不同阶段?每个阶段对应的方法是?
1.初始化: 在此阶段,react组件准备设置初始状态和默认道具
2.挂载: react组件已准备好挂载在浏览器DOM中。此阶段涵盖 componentWillMount() 和 componentDidMount ()生命周期方法。
3.更新: 在此阶段,组件以两种方式进行更新,即发送新道具和更新状态。此阶段涵盖了 shouldComponentUpdate(),componentWillUpdate()和componentDidUpdate() 生命周期方法
4.卸载: 在最后一个阶段,不需要该组件,并且可以从浏览器DOM上卸载该组件。此阶段包括 componentWillUnmount 生命周期方法。
4.什么是响应式设计?响应式设计的基本原理是什么?如何做?
1.响应式设计是什么?
响应式网站设计(Responsive Web design)是一种网络页面设计布局,页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整。
2.响应式网站常见特点:
1)同时适配PC + 平板 + 手机等
2)标签导航在接近手持终端设备时改变为经典的抽屉式导航
3)网站的布局会根据视口来调整模块的大小和位置
3.实现方式
响应式设计的基本原理是通过媒体查询检测不同的设备屏幕尺寸做处理,为了处理移动端,页面头部必须有meta声明viewport
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no”>
属性对应如下:
1)width=device-width: 是自适应手机屏幕的尺寸宽度
2)maximum-scale:是缩放比例的最大值
3)inital-scale:是缩放的初始化
4)user-scalable:是用户的可以缩放的操作
具体实现方式
- 弹性盒子(包括图片、表格、视频)和媒体查询等技术
- 使用百分比布局创建流式布局的弹性UI,同时使用媒体查询限制元素的尺寸和内容变更范围
- 使用相对单位使得内容自适应调节
- 选择断点,针对不同断点实现不同布局和内容展示
5.说说webpack中常见的loader?解决了什么问题?
1.是什么
loader 用于对模块的源代码进行转换,在 import 或"加载"模块时预处理文件
2.做什么
webpack做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。如下图所示:
在页面开发过程中,我们经常性加载除了js文件以外的内容,这时候我们就需要配置响应的loader进行加载
常见的loader
- style-loader: 将css添加到DOM的内联样式标签style里
- css-loader :允许将css文件通过require的方式引入,并返回css代码
- less-loader: 处理less
- sass-loader: 处理sass
- postcss-loader: 用postcss来处理CSS
- autoprefixer-loader: 处理CSS3属性前缀,已被弃用,建议直接使用postcss
- file-loader: 分发文件到output目录并返回相对路径
- url-loader: 和file-loader类似,但是当文件小于设定的limit时可以返回一个Data Url
- html-minify-loader: 压缩HTML
- babel-loader :用babel来转换ES6文件到ES
6.如何通过原生js实现一个节流函数和防抖函数?
防抖 在停止触发的一段时间后触发回调函数
const debounce = (func, wait = 50) => { let timer = 0 return function(...args) { if (timer) clearTimeout(timer) timer = setTimeout(() => { func.apply(this, args) }, wait) } }
节流 在一短时间内指触发一次
const throttle = function (fn, wait = 500) { let flg = true return function () { if (!flg) return; flg = false setTimeout(() => { fn.apply(this, arguments) flg = true }, wait); } }
7.说说你对koa中洋葱模型的理解?
Koa的洋葱模型是以next()函数为分割点,先由外到内执行Request的 逻辑,然后再由内到外执行Response的逻辑,这里的request的逻辑, 我们可以理解为是next之前的内容,response的逻辑是next函数之后 的内容,也可以说每一个中间件都有两次处理时机。洋葱模型的核心原 理主要是借助compose方法
8.说说你对webSocket的理解?
websocket,顾名思义就是web端的socket,其作用就是给web端提供了与httpserver端之间的长连接,使得httpserver在建立连接的任何时候都可以主动通知web页面事件,如果没有此协议存在的话,web端需要不断的通过轮询的方式去查询一些服务器端的状态。
9.for…in循环和for…of循环的区别?
- for…in 循环:只能获得对象的键名,不能获得键值,for…of 循环:允许遍历获得键值
- 对于普通对象,没有部署原生的 iterator 接口,直接使用 for…of 会报错,可以使用 for…in 循环遍历键名
- for…in 循环不仅遍历数字键名,还会遍历手动添加的其它键,甚至包括原型链上的键
- 无论是 for…in 还是 for…of 都不能遍历出 Symbol 类型的值,遍历 Symbol 类型的值需要用 Object.getOwnPropertySymbols() 方法。
- for…in 循环不仅遍历数字键名,还会遍历手动添加的其它键,甚至包括原型链上的键。
10.说说你对Object.defineProperty()的理解?
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
该方法接受三个参数,第一个参数是 obj:要定义属性的对象,第二个参数是 prop:要定义或修改的属性的名称或 Symbol,第三个参数是 descriptor:要定义或修改的属性描述符
函数的第三个参数 descriptor 所表示的属性描述符有两种形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符只能是这两者其中之一;不能同时是两者。
这两种同时拥有下列两种键值:
- configurable:是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。
- enumerable:当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。默认为 false。
React面试题
1.setState 是同步,还是异步的?
在React18之前
setState在不同情况下可以表现为异步或同步。
在Promise的状态更新、js原生事件、setTimeout、setInterval…中是同步的。
在react的合成事件中,是异步的。
react18之后。
setState都会表现为异步
18版本之前的解释
在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state 。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。
原因: 在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。
注意: setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
综上,setState 只在合成事件和 hook() 中是“异步”的,在 原生事件和 setTimeout 中都是同步的。
2.说说React Jsx转换成真实DOM过程?
- 使用React.createElement或JSX编写React组件,实际上所有的 JSX 代码最后都会转换成React.createElement(…) ,Babel帮助我们完成了这个转换的过程。
- createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
- ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实DOM
3.state 和 props有什么区别?
相同点:
- 两者都是 JavaScript 对象
- 两者都是用于保存信息
- props 和 state 都能触发渲染更新
不同点:
- props 是外部传递给组件的,而 state 是在组件内被组件自己>- 管理的,一般在 constructor 中初始化
- props 在组件内部是不可修改的,但 state 在组件内部可以进行修改
- state 是多变的、可以修改
4.react中懒加载的实现原理是什么?
随着前端应用体积的扩大,资源加载的优化是我们必须要面对的问题,动态代码加载就是其中的一个方案,webpack 提供了符合 ECMAScript 提案 的 import() 语法 ,让我们来实现动态地加载模块(注:require.ensure 与 import() 均为 webpack 提供的代码动态加载方案,在 webpack 2.x 中,require.ensure 已被 import 取代)。
在 React 16.6 版本中,新增了 React.lazy 函数,它能让你像渲染常规组件一样处理动态引入的组件,配合 webpack 的 Code Splitting ,只有当组件被加载,对应的资源才会导入 ,从而达到懒加载的效果。
引入
React.lazy 接受一个函数作为参数,这个函数需要调用 import() 。它需要返回一个 Promise,该 Promise 需要 resolve 一个 defalut export 的 React 组件。
// 不使用 React.lazy
import OtherComponent from ‘./OtherComponent’;
// 使用 React.lazy
const OtherComponent = React.lazy(() => import(‘./OtherComponent’))
使用
React.lazy 需要配合 Suspense 组件一起使用,在 Suspense 组件中渲染 React.lazy 异步加载的组件。如果单独使用 React.lazy,React 会给出错误提示。
Suspense 可以包裹多个动态加载的组件,这也意味着在加载这两个组件的时候只会有一个 loading 层,因为 loading 的实现实际是 Suspense 这个父组件去完成的,当所有的子组件对象都 resolve 后,再去替换所有子组件。这样也就避免了出现多个 loading 的体验问题。所以 loading 一般不会针对某个子组件,而是针对整体的父组件做 loading 处理。
// An highlighted block
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
5.说说你对react的理解?有哪些特性?
- 是什么
React,用于构建用户界面的 JavaScript 库,提供了 UI 层面的解决方案
遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效
使用虚拟DOM来有效地操作DOM,遵循从高阶组件到低阶组件的单向数据流
帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面
2.特点
- jsx语法
- 虚拟dom
- 单项数据绑定
- 声明式编程
- Component
6. 说说Real DOM和Virtual DOM的区别?优缺点?
真实dom
在页面渲染出的每个节点都是一个真实的DOM结构
优点
- 直接操作HTML,易用
缺点
- 解析速度慢,效率低,内存占用量高
- 性能差:频繁操作真实DOM,导致重绘、回流
虚拟dom
Virtual DOM 是一个轻量级的js对象,它最初只是real DOM的副本,也是一个节点树,它将元素、它们的属性和内容作为该对象及其属性。
优点
- 减少真实dom的频繁更新,减少重绘回流、占用内存少
- 跨平台:一套react代码可以多端运行
缺点
- 页面首次渲染时,由于多一层虚拟dom的计算,速度比正常慢些
区别
- 虚拟dom不会进行重绘和回流,而真实dom会频繁重排与重绘
- 虚拟dom的总损耗是”虚拟dom的增删改+真实dom的差异增删改+重排“;真实dom的消耗是”真实dom全部增删改+重排“
7.说说React中setState执行机制
8.说说react的事件机制?
react事件机制
- react自身实现了一套事件机制,包括事件的注册、事件的存储、事件的合成及执行等。
- react 的所有事件并没有绑定到具体的dom节点上而是绑定在了document 上,然后由统一的事件处理程序来派发执行。
- 通过这种处理,减少了事件注册的次数,另外react还在事件合成过程中,对不同浏览器的事件进行了封装处理,抹平浏览器之间的事件差异
9.说说你对fiber架构的理解?解决了什么问题?
1.是什么
React Fiber 是 Facebook 花费两年余时间对 React 做出的一个重大改变与优化,是对 React 核心算法的一次重新实现。从Facebook在 React Conf 2017 会议上确认,React Fiber 在React 16 版本发布
2.在react中主要做了以下操作
- 为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
- 增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
- dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行
3.从架构角度来看,Fiber 是对 React核心算法(即调和过程)的重写
4.从编码角度来看,Fiber是 React内部所定义的一种数据结构,它是 Fiber树结构的节点单位,也就是 React 16 新架构下的虚拟DOM
5. 原理
Fiber把渲染更新过程拆分成多个子任务,每次只做一小部分,做完看是否还有剩余时间,如果有继续下一个任务;如果没有,挂起当前任务,将时间控制权交给主线程,等主线程不忙的时候在继续执行
即可以中断与恢复,恢复后也可以复用之前的中间状态,并给不同的任务赋予不同的优先级,其中每个任务更新单元为 React Element 对应的 Fiber节点
10.说说React jsx转换成真实DOM的过程?
编译JSX
- 首先,JSX本质其实是javascript的语法扩展,和模板语言非常接近,但是其充分具备javascript的能力。但是其要在javascript生效的话,需使用到 Babel 进行编译,JSX在被编译后,会变成一个针对 React.createElement 的调用。
React.createElement 内部流程
- 首先,React.createElement 会接收三个参数:
第一个参数为 type,字符串类型,用于标识节点的类型,比如,div、p等,也可以是React组件类型或 React fragment类型。
第二个参数为 config,这是一个对象类型的参数,组件的所有属性都会键值对的形式存储在config中。
第三个参数为 children,这也是一个对象类型的参数,它记录的是组件标签之间嵌套的内容,也就是所谓的子节点或子元素。
createElement的大致流程为:
- .二次处理key、ref、self、source四个属性值;
- 遍历config,筛选可以提到props中的属性;
- .将children中的子元素推入childArray数组;
- .格式化defaultProps
- .将以上数据作为入参,发起ReactElement的调用,最终>- 由ReactElement返回虚拟Dom对象
最终将虚拟Dom传入ReactDom.render函数中,将其转变为真实Dom
流程
书写JSX代码 => Babel编译JSX => 编译后的JSX执行React.createElement的调用 => 传入到ReactElement方法中生成虚拟Dom => 最终返回给ReactDom.render生成真实Dom
11.说说Real diff算法是怎么运作的?
主要分为3层:tree层、component层、element层
- tree层:
tree层对DOM节点的跨层级移动的操作忽略不计,只对相同层级的DOM节点进行比较(即同一个父节点下的所有子节点),一旦发现节点不存在,直接删除掉该节点以及之下的所有子节点。- component层:
- 遇到同一类型的组件遵循 tree diff,进行层级对比
- 遇到不同类型的组件,直接将这个不同的组件判断为脏组件,并替换该组件和之下所有的子节点
- 在同一类型的两个组件中,当知道这个组件的虚拟dom没有任何变化,就可以手动使用shouldComponentUpdate()来判断组件是否需要进行diff,进一步的提升了diff效率和性能
- element层:
- element层对同一层级的元素节点进行比较
- 面对全新的节点时,执行插入操作
- 面对多余的节点时,执行删除操作
- 面对换位的节点时,执行移动操作
12.说说你对react hook的理解?
- 在函数组件里无法使用类组件里的方法于是就有了 hooks,可以让我们在函数组件里做一些在类组件里的操作
React中的常用的Hook方法:
UseState():
useState()用于为函数组件引入状态。在useState()中,数组第一项为一个变量,指向状态的当前值。类似this.state,第二项是一个函数,用来更新状态,类似setState
UseEffect():
useEffect()接受两个参数,第一个参数是你要进行的异步操作,第二个参数是一个数组,用来给出Effect的依赖项。只要这个数组发生变化,useEffect()就会执行
useRef():
相当于class组件中的createRef的作用,ref.current获取绑定的对象
UseContext():
接收context状态树传递过来的数据
UseReducer():
接受reducer函数和状态的初始值作为参数,返回一个数组,其中第一项为当前的状态值,第二项为发送action的dispatch函数
UseMemo()和useCallback():
接收的参数都是一样,第一个参数为回调,第二个参数为要依赖的数据
共同作用:仅仅依赖数据发生变化, 才会调用,也就是起到缓存的作用。useCallback缓存函数,useMemo 缓存返回值。
13.React组件之间如何通信
父组件向子组件传递:
父组件在调用子组件的时候,在子组件标签内传递参数,子组件通过props属性就能接收父组件传递过来的参数
子组件向父组件传递:
父组件向子组件传一个函数,然后通过这个函数的回调,拿到子组件传过来的值
兄弟组件之间的通信:
父组件作为中间层来实现数据的互通,通过使用父组件传递
父组件向后代组件传递:
使用context提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据
通过使用React.createContext创建一个context;
context创建成功后,其下存在Provider组件用于创建数据源,Consumer组件用于接收数据
Provider组件通过value属性用于给后代组件传递数据
如果想要获取Provider传递的数据,可以通过Consumer组件或者或者使用contextType属性接收
非关系组件传递:
将数据进行一个全局资源管理,从而实现通信比如react-redux
14.说说你对受控组件和非受控组件的理解?应用场景?
受控组件,简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据,一般需要初始状态和一个状态更新事件函数。
例如input框,首先在其上面绑定一个value,然后在绑定一个onChange()事件,实时更新输入的数据
非受控组件,简单来讲,就是不受我们控制的组件。
一般情况是在初始化的时候接受外部数据,然后自己在内部存储其自身状态。在需要时可以使用ref属性来获取对应的节点
应用场景
大部分时候推荐使用受控组件来实现表单,因为在受控组件中,表单数据由React组件负责处理。
如果选择非受控组件的话,控制能力较弱,表单数据就由DOM本身处理,但更加方便快捷,代码量少
15.说说react 中jsx语法糖的本质?
Jsx是语法糖,实质是js函数,需要babel来解析,核心函数是React.createElement(tag,{attrbuties},children),参数tag是标签名可以是html标签和组件名,attrbuties参数是标签的属性,children参数是tag的子元素。用来创建一个vnode,最后渲染到页面上。
16.说说package.json中版本号的规则?
第一部分为主版本号,变化了表示有了一个不兼容上个版本的大更改。
第二部分为次版本号,变化了表示增加了新功能,并且可以向后兼容。
第三部分为修订版本号,变化了表示有bug修复,并且可以向后兼容。
第四部分为日期版本号加希腊字母版本号,希腊字母版本号共有五种,分别为base、alpha、beta 、RC 、 release
如图所示
17.14.说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
1.是什么
react-redux react官方推出的redux绑定库,react-redux将所有组件分为两大类:UI组件和容器组件,其中所有容器组件包裹着UI组件,构成父子关系。容器组件负责和redux交互,里面使用redux API函数,UI组件负责页面渲染,不使用任何redux API。容器组件会给UI组件传递redux中保存对的状态和操作状态的方法。
@reduxjs/toolkit Redux 官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式,使用 Redux Toolkit 都可以优化你的代码,使其更可维护。
2.区别
- redux和组件进行对接的时候是直接在组件中进行创建。react-redux是运用Provider将组件和store对接,使在Provider里的所有组件都能共享store里的数据,还要使用connect将组件和react连接。
- 获取state的方式不一样
redux获取state是直接通过store.getState()。
react-redux获取state是通过mapStateToProps函数,只要state数据变化就能获取最新数据。- 触发action的方式不一样。
redux是使用dispatch直接触发,来操作store的数据。
react-redux是使用mapDispathToProps函数然后在调用dispatch进行触发
18.React性能优化的手段有哪些?
1、使用纯组件;
2、使用 React.memo 进行组件记忆(React.memo 是一个高阶组件),对 于相同的输入,不重复执行;
3、如果是类组件,使用 shouldComponentUpdate(这是在重新渲染组件之前触发的其中一个生命周期事件)生命周期事件,可以利用此事件来决定何时需要重新渲染组件;
4、路由懒加载;
5、使用 React Fragments 避免额外标记;
6、不要使用内联函数定义(如果我们使用内联函数,则每次调用“render”函数时都会创建一个新的函数实例);
7、避免在Willxxx系列的生命周期中进行异步请求,操作dom等;
8、如果是类组件,事件函数在Constructor中绑定bind改变this指向;
9、避免使用内联样式属性;
10、优化 React 中的条件渲染;
11、不要在 render 方法中导出数据;
12、列表渲染的时候加key;
13、在函数组件中使用useCallback和useMemo来进行组件优化,依赖没有变化的话,不重复执行;
14、类组件中使用immutable对象;
19.调和阶段setState干了什么?
1.代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。
2.经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;
3.在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;
4.在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
20.React合成事件的原理?
React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器。它根据 W3C 规范 来定义合成事件,兼容所有浏览器,拥有与浏览器原生事件相同的接口。
21.说说Connect组件的原理是什么?
connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])
作用:连接React组件与Redux Store
mapStateToProps允许我们将 store 中的数据作为 props 绑定到组件上
mapDispatchToProps将action作为props绑定到MyComp上。
mergeProps不管是stateProps还是dispatchProps,都需要和ownProps merge 之后才会被赋给MyComp。connect的第三个参数就是用来做这件事。通常情况下,你可以不传这个参数,connect就会使用Object.assign替代该方法。
首先connect之所以会成功,是因为Provider组件:
在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
接收Redux的store作为props,通过context对象传递给子孙组件上的connect
那connect做了些什么呢?
它真正连接 Redux 和 React,它包在我们的容器组件的外一层,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。
关于它的源码
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
代码如下
export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
constructor(props, context) {
// 从祖先Component处获得store
this.store = props.store || context.store
this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.state = { storeState: null }
// 对stateProps、dispatchProps、parentProps进行合并
this.updateState()
}
shouldComponentUpdate(nextProps, nextState) {
// 进行判断,当数据发生改变时,Component重新渲染
if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
this.updateState(nextProps)
return true
}
}
componentDidMount() {
// 改变Component的state
this.store.subscribe(() = {
this.setState({
storeState: this.store.getState()
})
})
}
render() {
// 生成包裹组件Connect
return (
<WrappedComponent {...this.nextState} />
)
}
}
Connect.contextTypes = {
store: storeShape
}
return Connect;
}
22.说说你对fiber架构的理解?解决了什么问题?
React Fiber 是 Facebook 花费两年余时间对 React 做出的一个重大改变与优化,是对 React 核心算法的一次重新实现。从Facebook在 React Conf 2017 会议上确认,React Fiber 在React 16 版本发布
在react中,主要做了以下的操作:
- 为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
- 增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
- dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行
23.前端跨域的解决方案(proxy)?
代码如下
proxy: {
'/api': {
target: 'http://e.dxy', // 后台接口域名
ws: true, //如果要代理 websockets,配置这个参数
secure: false, // 如果是https接口,需要配置这个参数
changeOrigin: true, //是否跨域
}
}
Vue面试题
1.Vuex有几种属性,它们存在的意义分别是什么?
有五种,分别是 State、 Getter、Mutation 、Action、 Module。
State
Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
State属性是Vuex的单一状态树
Getter
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数
Getter类似于Vue的 computed 对象。是根据业务逻辑来处理State,使得生成业务所需的属性。
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
Mutation是唯一用来更改Vuex中状态的方法。
Action
Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
Action是用来解决异步操作而产生的,它提交的是Mutation。
Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。 为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
Module是将Vuex模块化的对象,目的是更好的维护。
Html面试题
1.从浏览器地址栏输入url到显示页面的步骤?
1.浏览器的地址栏输入URL并按下回车。
2.浏览器查看浏览器缓存,系统缓存,路由器缓存是否存在该页面,有则显示,没有就像下执行。
3.DNS解析URL对应的IP。
4.根据IP建立TCP连接(三次握手)。
5.浏览器向服务器发起HTTP请求。
6.服务器处理请求,浏览器接收HTTP响应。
7.渲染页面,构建DOM树,CSSOM树。
8.关闭TCP连接(四次挥手)。
Git
1.git rebase 和git merge的理解?区别?
1.merge
Merge命令会保留所有commit的历史时间。每个人对代码的提交是各式各样的。尽管这些时间对于程序本身并没有任何意义。但是merge的命令初衷就是为了保留这些时间不被修改。这样也就形成了以merge时间为基准的网状历史结构。每个分支上都会继续保留各自的代码记录, 主分支上只保留merge的历史记录。子分支随时都有可能被删除。子分子删除以后,你能够看到的记录也就是,merge某branch到某branch上了。这个历史记录描述基本上是没有意义的。
2.rebase
这个命令会始终把你最新的修改放到最前头。比如你对主branch进行rebase以后, 你的所有修改就会在主branch当前所有的修改之前。你会更有信心保证你的代码运行畅通无阻。通过你自己的测试以后, 你就可以放心的把代码合并到主的branch里面了。
更多推荐
前端面试题整理
发布评论