2026React面试题笔试题
JS1.数组求共同元素出现频次常用reduce((执行完的值当前值)初始值)遍历,for in遍历对象会查原型链用hasOwnProperty只查当前对象上的属性function count(arr1.arr2){ const pre1 arr1.reduce((obj1,item1) { obj[item] (obj[item]||0)1 return obj1 },{}) const pre2 arr2.reduce((obj2,item2) { obj[item] (obj[item]||0)1 return obj2 },{}) let result {} for(const key in pre1){ if(pre2.hasOwnProperty(key)){ result[key] pre1[key]pre2[key] } } return result } console.log(count([1,2,2,1],[3,2,4,1])2.数组去冲重排序const arr [1,1,6,5,9,9,0,4,4,3] function getArr (arr){ const pre [...new Set(arr)].sort((a,b)a-b) return pre } //sort默认是字符串排序对数字排序需传比较函数(a,b)a-b是升序(a,b)b-a是降序 console.log(getArr(arr))3.多维数组扁平化const flatten arr arr.flat(Infinity) //Array.flat(depth)是ES6原生方法deph为扁平化深度传Infinity是表示支持任意维度嵌套4.求数组最大值最小值const arr [22,1,5,35,6,10] //1用Math和扩展运算符 const max Math.max(...arr) const min Math.min(...arr) //2.用reduce遍历 const max arr.reduce((pre,item)preitem?pre:item) const min arr.reduce((pre,item)preitem?item:pre) //3.排序后取首尾 const arr1 arr.sort((a,b)a-b) const max arr1[0] const min arr1[arr1.length-1]5.使用数组原生方法map将一个数组[1,2,3],输出为[{id:0},{id:1},{id:2}]const arr [1,2,3] const arr1 arr.map((item,index)({id:index})) console.log(arr1)字符串处理1.统计字符串中出现最多的字符,Object.values()会提取对象所有属性值得到一个值数组Math.max234会得到一组数字中的最大值扩展运算符把数组变成一组数字function getValue(str){ const obj1 str.split().reduce((obj,item){ obj[item] (obj[item]||0)1 return obj },{}) const max Math.max(...Object.values(obj1)) let result {} for (const key in obj1){ if(obj1[key]max){ result[key] max } } return result } console.log(getValue(aabbcdfghhhhp))函数封装防抖函数、节流函数、深拷贝1.假定有一个函数func参数个数未知实现函数newFunc,功能与func一致增加对参数类型的校验function newFunc(...args){//使用...args接收所有参数实现对未知个数参数的处理 const valid arg.every(item typeOf item number)//every遍历参数 if(!valid){ threw newError(参数类型错误必须是数字) } return func(...args) }解惑1:为什么...args可以接收所有参数...在这里是剩余参数语法作用是将函数调用时传入的多余的、未命名的参数收集到一个数组中它只能作为函数的最后一个形参不同于arguments对象是类数组需要通过Array.from()或[...arguments]转换为数组args是一个标准的数组可以直接使用map、filter等数组方法function fn(a,...args){ console.log(a)//第一个参数 console.log(args)//剩余所有参数组成的数组 } fn(1,2,3,4)//输出1[2,3,4] fn(hello)//输出hello|[]正因为它会把所有未匹配的参数收集成数组所以能实现‘接收所有参数’的效果2.实现构造函数Foo,使其实例最多只能存在一个单例模式确保一个类只有一个实例function Foo(){ // 如果已经有实例直接返回 if(Foo.instance){ return Foo.instance } //否则创建新实例并保存 Foo.instance this } //测试多次创建实例结果是同一个 const f1 new Foo() const f2 new Foo() console.log(f1 f2)//true指向同一个对象解惑2:构造函数的作用是创建并初始化对象实例对象是通过new关键字调用构造函数生成的代码中instance是自定义属性名挂载在构造函数Foo本身它的核心作用存储Foo的唯一实例实操代码题1.写一个函数用来获取URL链接上携带的参数要求最终返回结果是对象的键值对形式链接示例https://code.alipay.com/reques.html?a1b2c3d#pullfunction getUrlParams(url){ const params {} const str url.split(?)[0]//split会从分割形成两个字符串数组[..,a1b2c3d#pull] if(!str) return params const arr str.split()//[a1,..] arr.forEach((item){ [key,value] item.split() params[key] value }) return JSON.stringify(params)//要转码不然得到的是[object,object] } const url https://code.alipay.com/reques.html?a1b2c3d#pull getUrlParams(url)2.用React写一个提示窗组件要求弹窗绝对居中可使用指令调用。考点父子组件如何通信父组件侧定义是否显示弹窗的方法和属性把关闭的返回通过子组件传入子组件侧组件接收props在关闭按钮处绑定父组件传过来的关闭方法//子组件写弹窗和遮罩层和方法,forwardRef把ref暴露出去,useImperativeHandle自定义可调用方法 import React,{useState,memo} from react import ./Modal.css const Modal (props){ const {content,onClose} props //父组件传过来的 //暴露给父组件的方法. 正式开发不需要这样哦 //useImperativeHandle(ref,()({ //open(){setShow(true)},//打开弹窗 //close(){setShow(false)}//关闭弹窗 //})) //if(!show)return null; 不需要哦 return( div classNamemask div classNamecontent p{content}/p //直接使用父组件传来的关闭方法 onClose button classNamebtnClose onClick{onClose}关闭/button /div /div ) }) export default memo(Modal) //遮罩层mask样式用fixed布局固定宽高100%背景黑色半透明flex布局使子内容局中 //content样式设宽padding以及文字居中//父组件 import {useState} from react import Modal from ./Modal //导入子组件 function App(){ //定义是否显示的条件 const [showModal, setShowModal] useState(false); //开启弹窗 const handleClick () { setShowModal(true); }; //关闭弹窗 const handleClose () { setShowModal(false); }; return( div button onClick{handleClick}打开弹窗/button button onClick{handleClose}关闭弹窗/button //不用通过ref哦onClose 是一个关闭方法传过去了呢 这里要判断一下是否达到创建条件 {showModal Modal onClose{handleClose} content这是一个可被父组件指令式调用的弹窗/ } /div ) } export default App;父组件调用子组件方法1.父组件给子组件绑定useRef2.在父组件中的使用子组件的方法//父组件Parent.jsx import {useState,useRef} from react; import Modal from ./Modal; export default function Parent(){ const [modalContent,setMOdalContent] useState(宝宝乖); const ref useRef(null); const openModal (){ setModalContent(这是父组件传递给子组件的弹窗内容) //直接调用字组件的方法。完事这个方法是可以传参 ref.current?.handleCloseClick(); }; return( div button onClick{openModal}打开弹窗/button {/*父组件给子组件绑定ref*/} Modal ref{ref} content{modalContent} / /div ) }//子组件Modal.jsx import {useEffect} from react; export default function MOdal({content}){ //子组件内部函数 const handleCloseClick (){ console.log(我是子组件的方法) }; return( div classNamemask div classNamemodal div classNamemodal-content{content}/div /div /div ) }简答题1、useMemo与memo区别useMemo答缓存计算属性作用避免重复渲染新的计算场景购物车 计算价格memo答组件缓存渲染结果作用避免组件重复渲染保证props组件不重复创建 场景引入组件。备注props组件会做一次浅比较老的props和新的props比相等就不创建否则就创建useMemo 记值 memo 记组件2、怎么增加代码可读性1、组件拆分保持组件小而专一2、清晰命名3、类型校验 ts4、自定义hooks 抽离复杂逻辑5、常量提取3、rem和rpx怎么用Rem是相对单位。一般场景webRpx是小程序专有单位 屏幕宽度固定750rpx4、父组件数据变化重新渲染如何不影响到子组件当父组件更新时默认子组件会一起重新渲染。要避免这种情况可以使用 memo() 对子组件进行记忆化并结合 useMemo 或 useCallback 让传入的 props 引用保持稳定。这样当父组件 state 变化但与子组件无关时子组件就不会重新渲染提升性能。5、useEffect空依赖数组 执行一次 依赖不全会导致更新不一致• 不传依赖 → 每次渲染都执行• 传空数组 → 只执行一次挂载卸载• 传入依赖 → 当依赖变化时重新执•返回一个函数→这个函数是在页面销毁时执行的所以这里可以做销毁定时器或者方法6、useEffect 与 useLayoutEffect 的区别执行时机不同useEffect在组件渲染到屏幕之后异步执行useLayoutEffect会在浏览器进行布局和绘制之前同步执行对性能影响不同useEffect由于是异步执行不会阻塞页面的渲染useLayoutEffect由于是同步执行如果在其中执行的操作耗时较长会阻塞页面的渲染可能导致页面卡顿影响用户体验。使用场景不同一般使用useEffect发送网络请求获取数据、添加事件监听器useLayoutEffect一般用在获取DOM元素的样式、位置、大小等一个运行改变值state通过setSate改变 一个不可以改变值7、useState 如何拿到最新的值useState返回两个参数 一个是值一个是修改的方法可以在修改方法中在返回一个函数 就可以拿的修改后最新的值了通过useEffect/useMemo监听被监听的state发生变后就会立马获取到通过useRef 在state变化是赋值ref 之后就可以在其他地方使用8、useState和useRef的区别useState定义的值发生变化后页面会重新加载useRef他是直接操作dom 不出重新加载页面useState返回一个状态值和一个用于更新该状态的函数 [state, setState]useRef返回一个可变的 ref 对象 { current: initialValue }useState定义的值只能通过setState修改useRef 直接通过.current修改9、useEffect如何销毁方法或者事件在useEffect中在返回一个函数 这个函数会在页面销毁是执行useEffect(() {return () {//销毁方法处}}, []);10、受控组件和非受控组件区别受控组件就是组件内部的状态是通过自己的state去控制的完全受React控制 如一个文本框绑定了事件和value值 事件触发时立刻把最新的值通过setState把value的值修改成最新非受控组件就是通过浏览器去控制的如通过ref去获取他的值或者方法完全不受React控制11、为什么直接修改 props / state 不会触发更新答 React 是按「不可变数据」思想工作的。只有调用 setState 或 useState 的 setterReact 才能检测到变化。直接修改原对象不会触发 Diff对 React 来说它看起来“没变”。12、React类组件和函数组件之间的区别是什么1.定义方式:类组件是使用ES6的类来定义的需要继承React.Component。而函数组件则是简单的JavaScript函数。2.状态管理:在React的早期版本中类组件是唯一可以使用内部状态(state)的组件类型。函数组件是无状态的只能接收props。 但是从React16.8版本开始引入了Hooks这个新特性使得函数组件也可以使用状态以及其他React特性了。3.生命周期方法:类组件提供了生命周期方法而在引入Hooks之前函数组件无法使用这些生命周期方法。但是现在通过使用useEffect Hook,函数组件也可以模拟生命周期方法的行为。4.使用方式:类组件需要使用this关键字来访问props和状态而函数组件则可以直接访问这些值。13、常见的 hooks 有哪些、分别有什么用• useState用于在函数组件中添加状态管理• useEffect用于在函数组件中执行副作用操作• useContext用于在函数组件中访问React Context的值0. 附加 Hooks • useReducer用于管理复杂的状态逻辑• useCallback用于记忆函数引用避免不必要的重新渲染• useMemo用于记忆计算结果避免重复计算• useRef用于访问DOM元素或存储可变值• useImperativeHandle用于自定义向父组件暴露的实例值• useLayoutEffect在DOM更新后同步执行副作用• useDebugValue用于在React开发工具中显示自定义hook的标签14、请你简单说一下React 中的事件机制是怎样的React 有自己实现的一套事件系统叫 合成事件SyntheticEvent 。它会在组件挂载时把所有事件 委托到根节点 React 17 以后是 root 容器统一处理。当用户在子组件触发事件时React 会通过事件冒泡机制捕获并分发到对应的组件回调。这样可以减少事件绑定数量、提升性能同时屏蔽浏览器差异。15、那这个合成事件和原生 DOM 事件有什么区别事件合成是react自己实现一层封装它在内部统一不同浏览器的事件行为。React的事件不会被绑定到真实dom节点而是委托到根部节点。同时它的事件对象会被放入一个事件池事件执行完后被回收。相比 原生绑定dom节点上每个都需要单独注册16、js事件循环js事件循环是一种异步执行的机制因为js是单线程运行的运行在浏览器和node.js中的因为浏览器和node.js为它异步API提供了多线程支持执行是由上到下执行先执行同步在中间出现宏任务和微任务时将宏任务和微任务先放入任务队列等待处理将同步执行完毕从任务队列中先将微任务执行然后执行宏任务事件循环就是不断的判断主线程是否为空如果为空就将任务队列中的事件放到主线程中执行这个过程会不断循环直到执行完毕17、什么是宏任务和微任务宏任务和微任务都是指的异步任务普通同步代码如 console.log会在当前执行栈中执行而微任务和宏任务则涉及到异步操作宏任务MacrotaskssetTimeout 和 setInterval用于创建宏任务指定的回调函数会被放入宏任务队列中。I/O 操作诸如读写文件、操作数据库等异步任务。DOM事件例如点击事件、输入事件等。AJAX请求的回调函数AJAX完成时其回调函数会被放入宏任务队列中。微任务MicrotasksPromise的then方法Promise对象状态改变时其回调会被放入微任务队列。process.nextTick在Node.js环境中将回调函数放入当前执行栈的微任务队列中。18、宏任务和微任务的区别宏任务1.宏任务所处的队列就是宏任务队列2. 宏任务队列可以有多个3. 当宏任务队列的中的任务全部执行完以后会查看是否有微任务队列如果有先执行微任务队列中的所有任务如果没有就查看是否有宏任务队列微任务1. 微任务所处的队列就是微任务队列2. 只有一个微任务队列3. 在上一个宏任务队列执行完毕后如果有微任务队列就会执行微任务队列中的所有任务19、Promise是什么解决了什么问题回调地狱在使用回调函数处理异步操作时代码容易陷入回调地狱。这会导致代码难以阅读和维护因为每个异步操作都嵌套在上一个操作的回调函数中Promise.then复杂的错误处理在嵌套的回调中处理错误非常复杂因为每个回调函数都需要独立地处理错误Promise.catch并行异步操作在回调模式下并行执行多个异步操作并在所有操作完成后处理结果会变得非常复杂Promise.all/race/allSettled/any4增强可读性和可维护性嵌套的回调函数不仅难以阅读而且难以调试和维护aysnc await异步操作的控制反转在回调模式中异步操作的控制权在异步函数内部不易进行更复杂的流程控制。resolve/reject20、Promise 有哪些方法then()- 处理 Promise 的 fulfilled成功或 rejected失败状态支持链式调用。catch()- 专门处理 rejected 状态的错误是 then(null, onRejected) 的语法糖。‌‌1‌‌3finally()- 无论 Promise 成功或失败都会执行常用于清理操作如关闭加载动画不接收状态结果。‌‌1‌‌‌静态方法Promise.resolve()- 返回一个已解决的 Promise若参数是 Promise则直接返回该对象。‌‌3‌‌4Promise.reject()- 返回一个已拒绝的 Promise参数作为失败原因。‌‌3‌‌4Promise.all()- 并行执行多个 Promise全部成功时返回结果数组任一失败则立即拒绝。‌‌‌‌5Promise.allSettled()。- 等待所有 Promise 完成无论成功或失败返回包含每个结果的描述对象数组。‌‌‌‌6Promise.race()- 返回第一个状态改变的 Promise 的结果无论成功或失败。‌‌‌‌6Promise.any()- 返回第一个成功的 Promise 结果全部失败时返回聚合错误。‌‌21、Promiseaysnc awaitsetTimeout三者的区别语法差异Promise通过 .then、.catch 和 .finally 方法链式调用语法较为复杂。async/await基于 Promise但以同步风格编写异步代码语法更简洁、更具可读性。setTimeout用于延时执行代码通常用于模拟异步行为。错误处理不同Promise通过 .catch 方法处理错误。async/await通过 try...catch 块处理错误。setTimeout没有内置的错误处理机制需要在回调函数内部处理错误。应用场景不同Promise适用于多个异步操作的组合处理和链式调用。async/await适用于需要以同步风格编写异步代码的场景特别是当有多个异步操作时。setTimeout用于延时执行代码通常用于模拟异步行为或在某些操作后延时执行下一步。22、什么是原型链在JavaScript中每个函数都有一个prototype属性铺落头它指向一个对象这个对象包含可以被该函数实例共享的属性和方法。当创建一个对象时该对象会从它的构造函数那里继承prototype对象。当尝试访问一个对象的某个属性或者方法时如果该对象本身没有这个属性或方法JavaScript引擎会沿着原型链向上查找直到找到这个属性或方法为止。如果在整个原型链上都没有找到则认为该属性或方法不存在

相关新闻

最新新闻

日新闻

周新闻

月新闻