面试题练习第一篇

简介: 面试题练习第一篇

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

(1)用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案


(2)遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效


(3)使用虚拟 DOM 来有效地操作 DOM,遵循从高阶组件到低阶组件的单向数据流


(4)帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面


(5)react 类组件使用一个名为 render() 的方法或者函数组件return,接收输入的数据并返回需要展示的内容


特性:

JSX 语法
单向数据绑定
虚拟 DOM
声明式编程
Component

2.说说Real DOM和Virtual DOM的区别?优缺点

区别:

(1)虚拟 DOM 不会进行排版与重绘操作,而真实 DOM 会频繁重排与重绘

(2)虚拟 DOM 的总损耗是“虚拟 DOM 增删改+真实 DOM 差异增删改+排版与重绘”,真实 DOM 的总损耗是“真实 DOM 完全增删改+排版与重绘”


优缺点:


真实dom:

优点: 易用

缺点:


效率低,解析速度慢,内存占用量过高

性能差:频繁操作真实 DOM,易于导致重绘与回流

虚拟dom:

优点:


简单方便

能够有效避免真实 DOM 数频繁更新,减少多次引起重绘与回流,提高性能

跨平台

缺点:


在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化

首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,速度比正常稍慢

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

创建阶段:


constructor

getDerivedStateFromProps

render

componentDidMount


更新阶段


getDerivedStateFromProps

shouldComponentUpdate

render

getSnapshotBeforeUpdate

componentDidUpdate


销毁阶段


componentWillUnmount


4.说说React中setState执行机制

在 React 中,如果是由 React 引发的事件处理(比如通过 onClick 引发的事件处理),调用 setState 不会同步更新 this.state,除此之外的 setState 调用会同步更新 this.state


所谓的除此之外,指的是绕过 React,通过 addEventListener 直接添加的事件处理函数,还有通过 setTimeout/setInterval 产生的异步任务


5.说说react的事件机制

React基于浏览器的事件机制自身实现了一套事件机制,包括事件注册、事件的合成、事件冒泡、事件派发等,在React中这套事件机制被称之为合成事件


它所有的对象最终会被挂载到顶级对象上,其他任何dom节点上绑定的事件均无效


6.React组件之间如何通信

父组件向子组件传递:


父组件在调用子组件的时候,在子组件标签内传递参数,子组件通过props属性就能接收父组件传递过来的参数


子组件向父组件传递:


父组件向子组件传一个函数,然后通过这个函数的回调,拿到子组件传过来的值


兄弟组件之间的通信:


父组件作为中间层来实现数据的互通,通过使用父组件传递


父组件向后代组件传递:


使用context提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据


通过使用React.createContext创建一个context;


context创建成功后,其下存在Provider组件用于创建数据源,Consumer组件用于接收数据


Provider组件通过value属性用于给后代组件传递数据


如果想要获取Provider传递的数据,可以通过Consumer组件或者或者使用contextType属性接收


非关系组件传递:


将数据进行一个全局资源管理,从而实现通信


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

受控组件:即通过setState的形式控制输入的值及更新,

非受控组件:即通过dom的形式更新值,要获取其值可以通过ref的形式去获取。


受控组件:

简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据

class TestComponent extends React.Component {
  constructor (props) {
    super(props);
    this.state = { username: 'lindaidai' };
  }
  render () {
    return <input name="username" value={this.state.username} />
  }
}

当我们在输入框输入内容的时候,会发现输入的内容并无法显示出来,也就是input标签是一个可读的状态


这是因为value被this.state.username所控制住。当用户输入新的内容时,this.state.username并不会自动更新,这样的话input内的内容也就不会变了


如果想要解除被控制,可以为input标签设置onChange事件,输入的时候触发事件函数,在函数内部实现state的更新,从而导致input框的内容页发现改变


非受控组件:


简单来讲,就是不受我们控制的组件


一般情况是在初始化的时候接受外部数据,然后自己在内部存储其自身状态


当需要时,可以使用ref 查询 DOM并查找其当前值


应用场景:


904aec24732e44d192dfeae69d6670d8.png

8.说说你对fiber架构的理解?解决了什么问题?

解决的问题:

JavaScript引擎和页面渲染引擎两个线程是互斥的,当其中一个线程执行时,另一个线程只能挂起等待;如果 JavaScript 线程长时间地占用了主线程,那么渲染层面的更新就不得不长时间地等待,界面长时间不更新,会导致页面响应度变差,用户可能会感觉到卡顿


理解:

React Fiber 是对 React 做出的一个重大改变与优化,是对 React 核心算法的一次重新实现


主要做了:


为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务

增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行

dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行

9.说说react diff的原理是什么

react中diff算法主要遵循三个层级的策略:


tree层级

conponent 层级

element 层级

tree层不会做任何修改,如果有不一样,直接删除创建


component层从父级往子集查找,如果发现不一致,直接删除创建


element层有key值做比较,如果发现key值可以复用的话,就会将位置进行移动,如果没有,则执行删除创建

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

理解:


中间件是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的


Redux中,中间件就是放在就是在dispatch过程,在分发action进行拦截处理


本质上一个函数,对store.dispatch方法进行了改造,在发出 Action和执行 Reducer这两步之间,添加了其他功能


常用中间件:


redux-thunk:用于异步操作

redux-logger:用于日志记录


实现原理:


所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到getState和dispatch这两个方法


内部会将dispatch进行一个判断,然后执行对应操作


11.如何使用css实现一个三角形?

只需要设置上、左、右三条边即可,并且要上三角,就把左右border设为透明

.a{
Width:0px
Height:0px
Border-top:100px solid ‘red’
Border-left:100px solid ‘red’
Border-right:100px solid ‘red’
}

12.什么是强缓存和协商缓存?

强缓存是利用http请求头中的Expires和Cache-Control两个字段来进行控制,用来表示资源的缓存时间;浏览器不会像服务器发送任何请求,而是直接从本地缓存中读取文件并返回Status Code: 200 OK;


协商缓存是服务器用来确定缓存资源是否可用过期,向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源


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

使用React.createElement或JSX编写React组件,实际上所有的 JSX 代码最后都会转换成React.createElement(...) ,Babel帮助我们完成了这个转换的过程。


createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象


ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事务等机制并且对特定浏览器进行了性能优化,最终转换为真实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 都可以优化你的代码,使其更可维护


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

原理:

在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件


render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新dom树


触发时机:


类组件调用 setState 修改状态


函数组件通过useState hook修改状态


一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染


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

1.避免使用内联函数

2.使用react fragement 避免额外标记

3.使用immutable,减少渲染的次数,为了避免重复渲染,会在shouldComponentUpdate()中做对比,当返回true,执行render方法。immutable通过is方法完成对比

4.懒加载组件

5.事件绑定方式(在constructor中使用bind绑定性能更高)

6.服务端渲染

7.组件拆分,合理使用hooks


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

防抖:

const debounce = (func, wait = 50) => {
  let timer = 0
  return function(...args) {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(this, args)
    }, wait)
  }
}

节流:


export const throttle = function (fn, wait = 500) {
  let flg = true
  return function () {
    if (!flg) return;
    flg = false
    setTimeout(() => {
      fn.apply(this, arguments)
      flg = true
    }, wait);
  }
}

18.说说webpack中常见的loader?解决了什么问题?

常见loader:

css-loader:分析css 模块之间的关系,并合成⼀个css


style-loader:把css-loader生成的内容,用style标签挂载到页面的head中


less-loader:开发中,我们也常常会使用less、sass、stylus预处理器编写css样式,使开发效率提高,这里需要使用less-loader


raw-loader:在webpack中通过import方式导入文件内容,该loader并不是内置的,所以首先要安装,然后在 webpack.config.js 中进行配置


file-loader:把识别出的资源模块,移动到指定的输出⽬目录,并且返回这个资源在输出目录的地址(字符串)


url-loader:可以处理理file-loader中的所有事情,但是遇到图片格式的模块,可以选择性的把图片转成base64格式的字符串,并打包到js中,对小体积的图片比较合适,大图片不合适


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

  1. 使用监听模式或热更新热替换
  2. 开发环境不做无意义的操作
  3. 选择一个合适的devtool属性值
  4. 代码压缩用ParallelUglifyPlugin代替自带的 UglifyJsPlugin插件
  5. 使用fast-sass-loader代替sass-loader
  6. babel-loader开启缓存
  7. 不需要打包编译的插件库换成全局标签引入的方式
  8. 使用 DllPlugin 和 DllReferencePlugin
  9. 提取公共代码
  10. 使用HappyPack来加速构建
  11. 优化构建时的搜索路径
  12. 整理一下打包构建涉及的模块,分析看有哪些包是不需要打包的,只打包需要的模块(导出编译JSON文件)
  13. 使用ModuleConcatenationPlugin插件来加快JS执行速度
  14. 使用noParse
  15. 使用异步的模块加载
  16. 以模块化来引入

20.说说javascript内存泄漏的几种情况?

闭包、定时器、函数内部的this调用污染、全局变量污染


21.bind、call、apply 区别?如何实现一个bind?

call、apply、bind都是用于实现this指向改变的方式


区别:


call(参数1,参数2,参数3,…) :参数1代表this指向改变的方向,后面的参数代表传递的参数


apply(参数1,[a,b,c]):参数1代表this指向改变的方向,第二个参数是一个数组,数组中的内容代表要传递的参数


bind(参数1,…args):参数1代表this指向改变的方向,第二个参数代表传递的参数,可以分批传入,有函数作为返回值,需要调用后才会生效


实现一个bind:

//this指向window
function fn() {
    console.log(this);
}
let a = 123
// this指向预改变
const changeFn = fn.bind(a);
changeFn() // 调用返回函数,this指向a
fn()
相关文章
|
11月前
|
缓存 JavaScript 前端开发
面试题练习第二篇
面试题练习第二篇
108 0
|
2月前
|
存储 Java Linux
Java核心知识点整理大全27-笔记(已完结)
Java核心知识点整理大全27-笔记(已完结)
52 0
|
7月前
|
监控 Java 应用服务中间件
Java核心知识点整理大全6-笔记
当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。 在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞 (Blocked)和死亡(Dead)5 种状态。尤其是当线程启动以后,它不可能一直"霸占"着 CPU 独自 运行,所以 CPU 需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换
84 0
|
7月前
|
缓存 网络协议 算法
Java核心知识点整理大全3-笔记
初始标记: 只是标记一下 GC Roots 能直接关联的对象,速度很快,仍然需要暂停所有的工作线程
59 0
|
11月前
|
移动开发 JavaScript 前端开发
面试题练习第五篇
面试题练习第五篇
70 1
|
11月前
|
缓存 JavaScript 前端开发
面试题练习第三篇
面试题练习第三篇
158 0
|
11月前
|
缓存 JavaScript 前端开发
面试题练习第四篇
面试题练习第四篇
64 0
|
算法 JavaScript Devops
2022年的第一篇总结
今年有个新的计划,就是每过一段时间,比如说两个月,对自己的工作和生活进行总结和反思。
|
存储 自然语言处理 安全
C++从入门到精通(第一篇) :C++的入门(基础语法的整理)
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作 用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字 污染,namespace关键字的出现就是针对这种问题的。
124 0
C++从入门到精通(第一篇) :C++的入门(基础语法的整理)
|
开发框架 安全 .NET
C#学习(第一篇)
C# 又称“C Sharp”,是微软发布的一种简单、安全、稳定、通用的面向对象编程语言。
C#学习(第一篇)