🗒️八股文总结
type
status
date
slug
summary
tags
category
icon
password
Blocking
Blocked by
top
URL
Sub-item
Parent item
高频面试总结
html
script标签 async defer的区别
DOM事件流
JavaScript
闭包是什么? 闭包的用途?
this指向
前端性能优化
性能优化简述事件循环原理
async await的原理是什么?
async、awaitPromise then 第二个参数和catch的区别是什么?
- Promise 内部报错,reject 抛出错误后,由于就近原则,then 的第二个参数会先捕获到异常,catch 则无法获取异常。
- 但如果是 then 的第一个参数抛出错误,then 的第二个参数会捕获不到,只有 catch 能捕获。
错误捕捉/前端稳定性监控/计算首屏时间、白屏时间
普通函数和箭头函数的this指向问题
promise相关的特性
Promise全解析前端跨页面通信总结
css
BFC是什么? 哪些属性可以构成一个BFC呢?
postion属性大概讲一下, static是什么表现? static在文档流里吗?
flex
flex:1,flex:auto
当容器拉伸缩小的时候,元素也会弹性增大和缩小;但是
flex:1
在尺寸不足时依然与其他元素保持等分,会优先压缩内容,flex:auto
在尺寸不足时会优先最大化内容尺寸,挤压其他元素的空间。居中
工程化
Webpack的原理, plugin loader 热更新等等
one world
也无风雨也无晴
https://notion-next-plum-chi.vercel.app/article/ecd891de-2641-45fb-a21e-77d79dbe9ae9
组件库如何实现按需引入
one world
也无风雨也无晴
https://notion-next-plum-chi.vercel.app/article/ee8a6125-f52e-46dd-bc69-fcdcdb675347
react、Vue框架
react 与vue区别
为什么data属性是一个函数而不是一个对象?
组件实例对象
data
必须为函数,目的是为了防止多个组件实例对象之间共用一个data
,产生数据污染。采用函数的形式,initData
时会将其作为工厂函数都会返回全新data
对象聊聊 Vue 的双向数据绑定
new Vue()
首先执行初始化,对data
执行响应化处理,这个过程发生Observe
中
- 同时对模板执行编译,找到其中动态绑定的数据,从
data
中获取并初始化视图,这个过程发生在Compile
中
- 同时定义⼀个更新函数和
Watcher
,将来对应数据变化时Watcher
会调用更新函数
- 由于
data
的某个key
在⼀个视图中可能出现多次,所以每个key
都需要⼀个管家Dep
来管理多个Watcher
- 将来data中数据⼀旦发生变化,会首先找到对应的
Dep
,通知所有Watcher
执行更新函数
流程图如下:
Vue 的响应式原理中 Object.defineProperty 缺陷
1, 数据的变化是通过getter/setter来追踪的。因为这种追踪方式,有些语法中,即便是数据发生了变化,vue也检查不到。比如 向Object添加属性/ 删除Object的属性。
2,检测数组的变化,因为只是拦截了unshift shift push pop splice sort reverse 这几个方法
vue 父子组件生命周期
- 加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
- 子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
- 父组件更新过程
父beforeUpdate->父updated
- 销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
虚拟dom是什么? 原理? 优缺点?
用js模拟一颗dom树,放在浏览器内存中.当你要变更时,虚拟dom使用diff算法进行新旧虚拟dom的比较,将变更放到变更队列中,反应到实际的dom树,减少了dom操作。
虚拟DOM将DOM树转换成一个JS对象树,diff算法逐层比较,删除,添加操作,但是,如果有多个相同的元素,可能会浪费性能,所以,react和vue引入key值进行区分.
优点:
- 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
- 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
- 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、react native开发等等。
缺点:
- 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。
Vue 中的 computed 是如何实现的
computed本身是通过代理的方式代理到组件实例上的,所以读取计算属性的时候,执行的是一个内部的getter,而不是用户定义的方法。
computed内部实现了一个惰性的watcher,在实例化的时候不会去求值,其内部通过dirty属性标记计算属性是否需要重新求值。当computed依赖的任一状态(不一定是return中的)发生变化,都会通知这个惰性watcher,让它把dirty属性设置为true。所以,当再次读取这个计算属性的时候,就会重新去求值。
vue 和 react 在虚拟dom的diff上,做了哪些改进使得速度很快?
vue 和 react 里的key的作用是什么? 为什么不能用Index?用了会怎样? 如果不加key会怎样?
不用 key:
- 就地复用节点。在比较新旧两个节点是否是同一个节点的过程中会判断成新旧两个节点是同一个节点,因为 a.key 和 b.key 都是 undefined。所以不会重新创建节点和删除节点,只会在节点的属性层面上进行比较和更新。所以可能在某种程度上(创建和删除节点方面)会有渲染性能上的提升;
- 无法维持组件的状态。由于就地复用节点的关系,可能在维持组件状态方面会导致不可预知的错误,比如无法维持改组件的动画效果、开关等状态;
- 也有可能会带来性能下降。因为是直接就地复用节点,如果修改的组件,需要复用的很多节点,顺序又和原来的完全不同的话,那么创建和删除的节点数量就会比带 key 的时候增加很多,性能就会有所下降;
用 key:
- 维持组件的状态,保证组件的复用。因为有 key 唯一标识了组件,不会在每次比较新旧两个节点是否是同一个节点的时候直接判断为同一个节点,而是会继续在接下来的节点中找到 key 相同的节点去比较,能找到相同的 key 的话就复用节点,不能找到的话就增加或者删除节点。
- 查找性能上的提升。有 key 的时候,会生成 hash,这样在查找的时候就是 hash 查找了,基本上就是 O(1) 的复杂度。
- 节点复用带来的性能提升。因为有 key 唯一标识了组件,所以会尽可能多的对组件进行复用(尽管组件顺序不同),那么创建和删除节点数量就会变少,这方面的消耗就会下降,带来性能的提升。
vue 的keep-alive的作用是什么?怎么实现的?如何刷新的?
vue 是怎么解析template的? template会变成什么?
Vue.js在解析模板时,采用了以下步骤:
- 解析:Vue.js使用解析器将模板字符串转换为抽象语法树(AST)。
- 优化:Vue.js会对AST进行优化,找出静态内容(Static Content)和动态内容(Dynamic Content)。
- 静态内容是指在渲染过程中不会改变的部分,如纯文本。
- 动态内容是指依赖于响应式数据的部分,需要在每次数据变化时重新计算。
在解析和优化之后,模板会转换为一个渲染函数(Render Function)。渲染函数是一个JavaScript函数,它接收一个上下文对象作为参数,并返回一个虚拟DOM(VNode)树。
渲染函数的作用是根据数据的变化生成新的虚拟DOM树,并将其与旧的虚拟DOM树进行对比,找出需要更新的部分,然后将更新应用到实际的DOM上,以实现视图的更新。
总结起来,Vue.js通过解析器将模板转换为优化
后的渲染函数,渲染函数根据数据的变化生成虚拟DOM树,并将其与旧的虚拟DOM树进行对比和更新,最终映射到实际的DOM上完成视图的渲染。
JSX的本质是什么
JSX就是一个语法糖,全称JavaScript XML,是react定义的一种类似于XML的JS扩展语法,用来创建虚拟DOM。
react fiber
fiber意思是纤程,是一种数据结构或者执行单元。
react的渲染分为commit和render两个阶段,在react 16之前,render阶段是采用递归比较新旧两个虚拟dom树,找出需要更新的节点,这个过程是同步不可打断的,因为递归导致执行栈越来越深,如果打断就不可恢复。如果虚拟dom树比较复杂,则diff过程会一直占用js线程,导致界面卡顿,无法响应。
为了解决这个问题,react 16 使用了时间切片的思想,引入了新的react fiber架构,使得render阶段变为异步可打断的。通过先将虚拟dom树的每个节点转为fiber数据结构,并以链表的形式连接。然后根据链表顺序执行每个fiber,fiber本身也作为一个任务单元,每完成一个fiber任务后,会先判断是否有新的高优先级任务或着判断当前帧中是否还有剩余时间,如果没有时间则会把控制权交给浏览器,把剩余的fiber任务推到下一个帧中进行,这样避免一直占用js线程。当打断时会保存当前fiber索引,下次执行可以快速恢复。
fiber数据结构有很多种类,首先是作为任务单元,具备return、child、sibing属性作为遍历指针。作为静态的数据结构,该组件的类型(函数组件/类组件/原生组件等,statenode保存组件的真实dom引用。作为组件,保存了memorizedState,保存函数组件中的上一次渲染的hooks状态。作为动态的工作单元,保存了该组件本次更新中该组件改变的状态、要执行的工作。
react层面的性能优化
- 使用
React.memo
来实现浅比较,避免不必要的组件重新渲染。
- 在列表中使用键(Keys):
- 在渲染列表时,为每个列表项提供唯一的键(key)。
- 使用稳定的标识符作为键,避免将索引作为键,以确保正确的组件重用和更新。
- 使用虚拟滚动和分页:
- 对于大型列表或数据集,考虑使用虚拟化技术,如
react-virtualized
或react-window
,以减少渲染和内存消耗。 - 如果可能,将数据进行分页加载,只渲染当前可见的部分数据。
- 使用
React.lazy
和Suspense
实现按需加载组件: - 对于较大的组件或路由页面,可以使用
React.lazy
和Suspense
实现按需加载,即在需要时才进行组件加载,而不是在应用启动时一次性加载所有组件。这样可以提高应用程序的性能和加载速度。
- 使用 useCallback 和 useMemo:
- 使用
useCallback
缓存回调函数,避免不必要的函数重新创建。避免作为props,导致子组件重新渲染。 - 使用
useMemo
缓存计算结果,避免不必要的重复计算。
- 避免在渲染期间执行副作用:
- 尽量避免在渲染期间执行昂贵的副作用操作,如网络请求或计算密集型任务。
- 使用
useEffect
的依赖项数组,确保副作用只在特定依赖项变化时执行。
- 开启SSR(服务端渲染)
useEffect 与 useLayoutEffect 的区别
useEffect
和 useLayoutEffect
都是 React 中的 Hook,用于在函数组件中执行副作用操作。它们之间的主要区别在于它们的调用时机。useEffect
useEffect
它在组件渲染完成后异步执行的函数。- 副作用函数会在浏览器绘制完成后才会执行,因此它不会阻塞页面的更新。
- 适合大多数副作用操作,比如数据获取、订阅事件、定时器等。
useLayoutEffect
useLayoutEffect
是同步执行的,它会在组件渲染完成后立即调用副作用函数。- 副作用函数会在浏览器绘制之前执行,因此它可能会阻塞页面的更新。
- 通常用于需要在 DOM 更新之前执行的副作用操作,比如测量 DOM 元素尺寸、处理布局等。
总结:
- 如果你的副作用操作不需要同步执行,并且不会影响组件的布局和渲染,可以使用
useEffect
。
- 如果你的副作用操作需要同步执行,并且可能影响组件的布局和渲染,可以使用
useLayoutEffect
。
useCallback与useMemo区别
useCallback
缓存的是函数,适用于避免不必要的函数重新创建。
useMemo
缓存的是函数的返回值,适用于避免不必要的计算开销。
redux原理
虚拟列表怎么实现?
合成事件
先讲了一下React合成事件的优势:
1. 抹平不同浏览器直接的差异,提供统一的API使用体验
2. 通过事件委托的方式统一绑定和分发事件,有利于提升性能,减少内存消耗。
合成事件的绑定及分发流程:
1. React应用启动时,会在页面渲染的根元素上绑定原生的DOM事件,将该根元素作为委托对象
2. 在组件渲染时,会通过JSX解析出元素上绑定的事件,并将这些事件与原生事件进行一一映射
3. 当用户点击页面元素时,事件会冒泡到根元素,之后根元素监听的事件通过
dispatchEvent
方法进行事件派发
4. dispatchEvent
会根据事件的映射关系以及DOM元素找到React中与之对应的fiber节点
5. 找到fiber节点后,将其绑定的合成事件函数加到一个函数执行队列中
6. 最后则依次执行队列中的函数完成事件的触发流程React的patch流程
- React新版架构新增了一个
Scheduler调度器
主要用于调度Fiber节点的生成和更新任务
- 当组件更新时,
Reconciler协调器
执行组件的render方法生成一个Fiber节点
之后再递归的去生成Fiber节点
的子节点
- 每一个
Fiber节点
的生成都是一个单独的任务,会以回调的形式交给Scheduler
进行调度处理,在Scheduler
里会根据任务的优先级去执行任务
Scheduler
按照优先级执行任务时,会异步的执行,同时每一个任务执行完成之后,都会通过requestIdleCallBack
去判断下一个任务是否能在当前渲染帧的剩余时间内完成
- 如果不能完成就发生中断,把线程的控制权交给浏览器,剩下的任务则在下一个渲染帧内执行
- 整个
Reconciler
和Scheduler
的任务执行完成之后,会生成一个新的workInProgressFiber
的新的节点树,之后Reconciler
触发Commit阶段
通知Render渲染器
去进行diff
操作,也就是我们说的patch
流程
使用setCount修改数据后,到页面重新渲染,整个流程是怎么样的
初始化状态:使用
useState
定义一个状态变量和对应的更新函数。例如:const [count, setCount] = useState(0);
执行
setCount(count + 1)
后,到页面重新渲染的整个流程如下:1)当你调用
setCount(count + 1)
,React会记录这个更新操作,并将新的值(count + 1
)存储在内部。2)React会将组件标记为“脏”(dirty),表示需要重新渲染。
3)组件函数将被再次执行,这一次执行过程中会重新计算组件的UI。在这个过程中,
count
的值被更新为新的值(count + 1
),这将反映在生成的UI中。4)React会将前后两次渲染生成的虚拟DOM树进行比较,找出变化的部分。在这种情况下,
count
的值发生了变化,因此会更新与count
相关的部分。5)只有变化的部分会被重新渲染,这样可以提高性能。React会将变化的部分转换为实际的DOM操作,更新到页面上。
6)页面更新完成后,用户将看到更新后的页面,其中包含了新的
count
值的呈现。总结起来,执行
setCount(count + 1)
后,React会在后续的重新渲染过程中更新组件的UI,使其反映新的状态值。这样,页面就会显示更新后的数据。react和vue的diff算法
正常的两个树比较复杂度是n2,为了优化性能,react做了一些优化
- 树diff,只比对同级的dom节点。因为跨层级的节点移动场景很少
- 组件diff,如果组件类型不一样,则不再进行比对,直接替换新的组件
- 同一层级的子节点比较,以通过标记 key 的方式进行列表对比。(基于节点进行对比),尽可能的复用节点。
多节点diff更新过程
Diff算法
的整体逻辑会经历两轮遍历:第一轮遍历:处理
更新
的节点。第二轮遍历:处理剩下的不属于
更新
的节点。react16和react17的区别?
1、React16中JSX会转换为“React.createElement”,而react17不会---(新的JSX转换);
2、React17不再在后台的文档级别附加事件处理程序,而React16会---(事件代理更改);
3、React16中有事件池,React17去除了事件池。
react事件机制
class组件和函数组件的区别
类组件的缺点 :
- 大型组件很难拆分和重构,也很难测试。
- 业务逻辑分散在组件的各个方法之中,导致重复逻辑或关联逻辑。
- 组件类引入了复杂的编程模式,比如 render props 和高阶组件。
- 难以理解的 class,理解 JavaScript 中
this
的工作方式。
区别:
- 性能
函数组件的性能比类组件的性能要高,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。
- 状态
hooks出现之前,函数组件
没有实例
,没有生命周期
,没有state
,没有this
,所以我们称函数组件为无状态组件。 hooks出现之前,react中的函数组件通常只考虑负责UI的渲染,没有自身的状态没有业务逻辑代码,是一个纯函数。它的输出只由参数props决定,不受其他任何因素影响。
- 调用方式 函数组件重新渲染,将重新调用组件方法返回新的react元素。类组件重新渲染new一个新的组件实例,然后调用render类方法返回react元素,这也说明为什么类组件中this是可变的。
react和vue区别
ts
Type 和 interface 的区别
typescript is这个关键字是做什么呢?
在 TypeScript 中,
is
是一个用于类型判断的关键字。它可以用来在运行时检查一个值是否具有特定的类型,并返回一个布尔值。infer关键字
类型推断,表示在
extends
条件语句中声明待推断的类型变量。void和never
浏览器
进程与线程
浏览器页面渲染机制
JavaScript的加载、解析与执行会阻塞DOM的构建。也就是说,在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建
但是如果遇到带有async和defer的script标签,就会异步请求这些资源,不会阻塞页面渲染
浏览器渲染过程分为:构建DOM -> 构建CSSOM -> 构建渲染树 -> layout布局 -> 绘制
垃圾回收
网络
强缓存、协商缓存
从输入URL到页面加载发生了什么?
webscoket的连接原理
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它提供了一种在客户端和服务器之间进行实时数据传输的方式。下面是 WebSocket 连接的原理:
- 建立握手:客户端发起 WebSocket 连接时,首先会发送一个 HTTP 请求,请求头中包含了一些特定的字段,如 Upgrade、Connection、Sec-WebSocket-Key 等。这个请求被服务器接收后,会进行一些验证和协议升级的操作。
- 握手响应:服务器接收到客户端的握手请求后,会发送一个 HTTP 响应,响应头中也包含了一些特定的字段,如 Upgrade、Connection、Sec-WebSocket-Accept 等。这个响应告知客户端握手成功,可以开始进行 WebSocket 通信。
- 建立连接:客户端收到服务器的握手响应后,会完成 WebSocket 连接的建立。此时,客户端和服务器之间的 TCP 连接已经建立,后续的数据传输将通过这个连接进行。
- 数据传输:一旦 WebSocket 连接建立成功,客户端和服务器就可以通过这个连接进行双向的数据传输。无论是客户端还是服务器,都可以通过 send() 方法发送数据,对方接收到数据后会触发相应的事件进行处理。
- 保持连接:WebSocket 连接是持久化的,它可以保持在打开状态,不需要频繁地建立和关闭连接。客户端和服务器可以随时发送和接收数据,保持实时通信。
- 关闭连接:当客户端或服务器决定关闭 WebSocket 连接时,它们可以发送一个关闭帧来终止连接。关闭帧是一种特殊的数据帧,用于通知对方关闭连接。一旦连接关闭,客户端和服务器将无法再进行数据传输。
总结来说,WebSocket 连接的原理是通过建立握手、升级协议、建立 TCP 连接等步骤来实现客户端和服务器之间的实时双向通信。这种连接是持久化的,可以保持在打开状态,并且可以随时发送和接收数据。
301 302 304的区别
- 301 表示永久重定向,客户端应该更新链接到新的 URL。
- 302 表示临时重定向,客户端可以在将来的请求中使用新的 URL,但不需要更新链接。
- 304 表示资源未修改,客户端可以直接从缓存中获取资源,无需重新下载。
https是如何保证安全的? 是如何保证不被中间人攻击的?
HTTPS 通过加密通信和数字证书验证来保证安全性并防止中间人攻击。加密通信保护数据的机密性和完整性,数字证书验证确保与正确的服务器建立连接,防止被伪装的服务器。
- 加密通信:
- HTTPS 使用 SSL(Secure Sockets Layer)或 TLS(Transport Layer Security)协议进行加密通信。客户端和服务器之间的通信数据会在传输过程中进行加密,防止第三方窃听和篡改数据。
- 在建立连接时,客户端发送一个加密握手请求给服务器,服务器将自己的公钥发送给客户端。客户端使用服务器的公钥来加密通信中的对称密钥,然后发送给服务器。服务器使用私钥解密该对称密钥,从而建立起加密的通信。
- 数字证书验证:
- 服务器在建立 HTTPS 连接时,会使用由受信任的证书颁发机构(Certificate Authority,CA)签发的数字证书。证书中包含了服务器的公钥和一些其他信息。
- 客户端在收到服务器的数字证书后,会验证证书的有效性。验证包括检查证书的签名是否有效、证书是否过期、以及证书中的域名是否与访问的域名匹配。
- 如果证书验证成功,客户端将信任服务器的公钥。否则,客户端会发出警告或中止连接。
Http各版本分别做了哪些改进?说一下 http 和 https?
HTTP 1.0:
最早的HTTP版本,采用短连接方式,每次请求都需要建立和关闭TCP连接。它的主要特点是简单,但存在以下问题:
- 每个请求都需要建立新的TCP连接,造成了较大的开销。
- 不能复用连接,无法进行流水线处理,导致效率低下。
HTTP 1.1:
引入了持久连接(Keep-Alive)和流水线技术,以提高性能。主要改进包括:
- 引入了持久连接,允许多个请求和响应复用同一个TCP连接,减少了连接建立和关闭的开销。
- 引入了流水线处理,可以同时发送多个请求,无需等待前一个请求的响应。
HTTP 2.0:
将数据传输方式从文本格式改为二进制格式,并引入了多路复用技术。主要改进包括:
- 使用二进制帧替代了HTTP 1.x的文本格式,减少了数据量和解析开销。
- 引入了多路复用技术,可以在一个TCP连接上同时发送多个请求和响应,提高了并发性能。
- 支持服务器主动推送(Server Push),可以在客户端请求之前将相关资源主动推送给客户端。
HTTP 3.0:
基于UDP协议,并使用QUIC(Quick UDP Internet Connections)传输协议。主要改进包括:
- 使用UDP协议替代了TCP协议,减少了延迟和拥塞控制的问题。
- 使用QUIC协议,提供可靠性、安全性和流量控制等功能。
- 使用TLS 1.3作为底层安全协议。
HTTP 3.0基于udp的话, 如何保证可靠的传输?
TCP和UDP最大的区别是什么?
1)TCP 面向有连接; UDP:面向无连接
2)TCP 要提供可靠的、面向连接的传输服务。TCP在建立通信前,必须建立一个TCP连接,之后才能传输数据。TCP建立一个连接需要3次握手,断开连接需要4次挥手,并且提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端
3)UDP不可靠性,只是把应用程序传给IP层的数据报发送出去,但是不能保证它们能到达目的地
4)应用场景
TCP效率要求相对低,但对准确性要求相对高的场景。如常见的接口调用、文件传输、远程登录等
UDP效率要求相对高,对准确性要求相对低的场景。如在线视频、网络语音电话等
安全
中间人攻击
中间人攻击过程如下:
1)客户端向服务器发送建立连接的请求
2)服务器向客户端发送公钥
3)攻击者截获公钥,保留在自己手上
4)然后攻击者自己生成一个【伪造的】公钥,发给客户端
5)客户端收到伪造的公钥后,生成加密的秘钥值发给服务器
6)攻击者获得加密秘钥,用自己的私钥解密获得秘钥
7)同时生成假的加密秘钥,发给服务器
8)服务器用私钥解密获得假秘钥
9)服务器用假秘钥加密传输信息
防范方法:
服务端在发送浏览器的公钥中加入CA证书,浏览器可以验证CA证书的有效性
xss、csrf
场景题
微信扫码登录

代码题
实现一个节流函数? 如果想要最后一次必须执行的话怎么实现?
实现一个批量请求函数, 能够限制并发量?
数组转树结构
- 举例
去除字符串中出现次数最少的字符,不改变原字符串的顺序。
- 举例
“ababac” —— “ababa” “aaabbbcceeff” —— “aaabbb”
不定长二维数组的全排列
- 两个字符串对比, 得出结论都做了什么操作, 比如插入或者删除
sleep函数
节流防抖
EventEmitter
koa洋葱模型
遇到退格字符就删除前面的字符, 遇到两个退格就删除两个字符
实现一个函数, 可以间隔输出
实现LRU算法
深拷贝
代码题答案
coding
lxw15337674 • Updated Sep 30, 2023