• 【面试题】最新2023前端面试题


     

     给大家推荐一个实用面试题库

    1、前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

    • 瀑布流列表对于请求过的数据是否做优化?了解虚拟滚动(虚拟列表)吗?

      这题是基于我的项目介绍问的。虚拟列表是在处理用户滚动时,只改变列表在可视区域的渲染部分,它可以提高页面渲染性能,减少数据过多时的卡顿。下面是一个简单的虚拟列表demo:

    1. function FixedSizeList(props){
    2. const {{containerHeight,itemCount,itemHeight}} = props; // 容器高度,列表数量,列表项高度
    3. const [scrollTop,setScrollTop] = useState(0)
    4. const items = [];
    5. // 渲染列表第一个index
    6. let startIdx = Math.floor(scrollTop / itemHeight);
    7. // 渲染列表最后一个index
    8. let endIdx = Math.floor((scrollTop+containerHeight)/itemHeight);
    9. // 在可视区外缓存列表项数量
    10. const paddingCount = 2;
    11. startIdx = Math.max(startIdx - paddingCount,0);
    12. endIdx = Math.min(endIdx + paddingCount,itemCount-1)
    13. for(let i = startIdx;i <= endIdx;i++) {
    14. items.push(<Component key={i} index={i}
    15. style={{height:itemHeight}}/>)
    16. }
    17. const top = startIdx * itemHeight;
    18. const contentHeight = itemHeight * itemCount;
    19. return (
    20. <div style={{height:containerHeight,overflow:'auto'}}
    21. onScroll={
    22. (e) => {
    23. // 处理渲染有导致的白屏问题
    24. // 改为同步更新
    25. flushSync(() => {
    26. setScrollTop(e.target.scrollTop)
    27. })
    28. }
    29. }
    30. >
    31. <div style={{height:contentHeight}}>
    32. <div style={{height:top}}>div>
    33. {items}
    34. div>
    35. div>
    36. )
    37. }
    38. 复制代码
    • 重排重绘

      重排:当DOM的变化影响了元素的几何信息(DOM对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。修改元素的尺寸、增加删除可见的元素、操作Offset相关属性等都会引起重排。
      重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。如修改元素的颜色等。
      如何减少重排、重绘:

      1. 分离读写操作:即在使用offset相关属性进行读操作之前,完成所有改变DOM的写操作。
      2. 集中改变样式:将样式统一写在一个类名上,再将该类名加到属性上。
      3. 离线修改dom:在要操作dom之前,通过display隐藏dom,当操作完成之后,才将元素的display属性为可见;或者通过使用DocumentFragment创建一个dom碎片,在它上面批量操作dom,操作完成之后,再添加到文档中,这样只会触发一次重排。
      4. 设置position属性为absolutefixed
      5. 启用gpu加速:transform: translate3d(10px, 10px, 0);
    • 虚拟DOM

    • 类组件/函数组件开发区别

    • 实现自定义hook (对可以上下/左右滑动的滑块定义hooks)

      平时自己写自定义hooks比较少,所以这题面试官引导了挺久,还是没写出来/(ㄒoㄒ)/

      1. const onSlide = (dir) => {
      2. console.log(dir)
      3. }
      4. const { domRef:domRef1 } = useSlide(onSlide,'v');
      5. const { domRef:domRef2 } = useSlide(onSlide,'h');
      6. return (
      7. <div className="App">
      8. <input type="range" ref={domRef1}/>
      9. <input type="range" ref={domRef2} style={{transform:'rotate(-90deg)',marginTop:'55px'}}/>
      10. div>
      11. )
      12. 复制代码
      1. // 自定义 hooks useSlide
      2. const useSlide = (cb,direction) => {
      3. const domRef = useRef(null);
      4. const handleUp = (e) => {
      5. if(direction==='v'){
      6. // cb(e.clientX)
      7. cb(e.target.value);
      8. }else if(direction==='h'){
      9. // cb(e.clientY)
      10. cb(e.target.value)
      11. }
      12. }
      13. useEffect(() => {
      14. domRef.current.addEventListener('mouseup',handleUp)
      15. return () => {
      16. domRef.current.removeEventListener('mouseup',handleUp)
      17. }
      18. },[])
      19. return {
      20. domRef
      21. }
      22. }
      23. 复制代码
    • js数据类型,简单数据类型和复杂数据类型的区别

    • 原型链 原型对象

    • Promise与js事件机制

    • 数组扁平化(堆栈写法,非递归)

      1. const flatter = (arr) => {
      2. let stack = [...arr];
      3. let res = [];
      4. while(stack.length){
      5. let num = stack.pop();
      6. if(Array.isArray(num)) {
      7. stack.push(...num);
      8. } else {
      9. res.push(num);
      10. }
      11. }
      12. return res.reverse();
      13. }
      14. 复制代码
    • 玩石子游戏(算法)
      一共n颗石子,两个人轮流拿,每次可以拿1或2或3颗,最后一次将石子取完的人输,判断自己最后是赢是输?

      我一开始想能不能用动态规划去解,面试官说我想复杂了。当最后剩 4 颗石子的时候,无论我们怎么取都可以获胜;当剩 8 颗石子的时候,我们一定可以控制最后剩下 4 颗石子...所以我们只要 判断石子的数量是否是 4 的倍数 即可判断自己最后是否可以获胜。


    哈啰 已oc

    1. 面试官非常年轻,好像就已经是技术专家了,好羡慕,人也很好,整体面下来的感觉还是不错的。
    2. 复制代码
    • cors跨域原理

      通过设置响应头Access-Control-Allow-xxx字段来设置访问的白名单、可允许访问的方式等

      1. module.exports = async (ctx,next) => {
      2. // 设置响应头
      3. // 允许访问跨域服务的白名单 *允许所有
      4. ctx.set('Access-Control-Allow-Origin','*');
      5. ctx.set('Access-Control-Allow-Headers','Content-Type');
      6. ctx.set('Access-Control-Allow-Methods','GET,POST,OPTIONS');
      7. // OPTIONS 获取资源允许访问的方式
      8. // 其实在正式跨域之前浏览器会根据需要发起一次预检也就是option请求用来让服务端返回允许的方法
      9. await(next())
      10. }
      11. 复制代码
    • 跨域拦截 是浏览器拦截还是服务器拦截

      跨域是浏览器的同源策略造成的,同源是指"协议+域名+端口"三者相同,为了保证浏览器安全对响应的数据进行拦截,若发现是非同源的资源浏览器进程会把响应体丢弃。所以跨域拦截是浏览器进行拦截

      跨域是为了阻止用户读取到另一个域名下的内容,跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。通过表单的方式可以发起跨域请求,因为表单并不会获取新的内容,所以可以发起跨域请求。

    • 假设我现在在淘宝,要去百度,我还会携带上淘宝的cookie吗?

      不会。cookie中,domain 属性指定了 cookie 的所属域名,path 属性用来指定路径;这两个属性决定了服务器发送的请求是否带上这个cookie。淘宝的 cookie 和百度的域名、路径不一致,所以访问百度不会带上淘宝的cookie

    • 淘宝跳转到天猫页面为什么不需要重新登陆( taobao.com 和 tmall.com )?

      这是因为淘宝和天猫页面设置了单点登录SSO,在多个系统的集群里,用户只需一次登陆,其他系统也会感知到用户登陆,不需要用户重新输入用户名密码登陆。

      在淘宝和天猫之间部署一台专门用作登录的服务器,相当于实现一个中转站,这个中转站存放着需要共享登录状态服务应用的 session 信息,它就相当于一把钥匙,当用户进行应用跳转的时候都会来中转站看一看,如果 session 存在就直接使用这把钥匙把通往另一个应用的门打开,如果不在就得先确认用户身份(登录)制造 session 钥匙存在中转站再把门打开,用户的身份存储和身份的有效时间都是中转站说了算,统一管理的。

    • http协议的特点

      1. 灵活方便:支持传输多种形式的内容
      2. 可靠传输:基于tcp/ip
      3. 请求-应答:具有发送方和接收方
      4. 无状态:每次请求都是独立无关的,不会记住上一次的状态
    • BEM 命名规范

      B:block E:element M:modefiled 语义性好,模块化,组件化,可复用
      这是面试官看到我的掘金第一篇文章来问的,有兴趣的朋友可以看看哦。BEM-实战淘宝订单模块

    • flex:1的含义, flex:1和flex:2的区别

      flex 是 flex-grow ,flex-shrink ,flex-basis的缩写
      flex:1
      flex-grow:1若存在剩余空间根据剩余空间进行放大 ;
      flex-shrink:1若空间不够,将内容缩小;
      flex-basis:0% 内容本来大小

    • var a = [],为什么可以直接使用a.push(),a.pop()

      a 通过对象字面量的方式生成一个数组对象实例,可以通过原型链查找方法,使用到Array原型上的pushpop方法。

    • var a = new A(),a 和 A 的关系,A 和 Function 的关系

      a 是 A 的一个实例对象,a 的__proto__ 指向 A 的 prototype,A 的__proto__ 指向 Function 的 prototype

    • 浏览器事件机制 event loop

    • Primise.then 中的微任务在下一轮还是这一轮执行

    • commonjs之后为什么提出es molule,两个模块的特点

      commonjs 导出(module.exports),导入(require)。
      可以动态加载语句,发生在代码运行时,模块是同步加载的,只要加载完成才能进行后续操作;模块可以多次加载,但只会在第一次加载时运行一次,结果会被缓存,下次 加载直接读取缓存结果,除非清除缓存。导出的值的拷贝的,可以修改,模块内的修改不会影响拷贝的值,代码出错不好排查。
      esmodule 导出(export default),导入(import from)
      静态的,只能声明在文件最顶部,发生在代码编译时;导出的值存在映射关系引用,是可读的,不可修改

    • 函数式组件和类组件的区别

    • usestate 重复修改多次,会渲染多次吗? 什么时机触发渲染?

      • 如果useState同步代码中重复修改多次,只会渲染一次。因为出于性能考虑,React 会把多个 setState() 调用合并成一个调用,这也是state批量更新机制。React 会将该 state “冲洗” 到浏览器事件结束的时候,再统一地进行更新,这时才会触发渲染。
      • 而如果setState异步代码(如 setTimeout、async await)中重复修改多次,渲染会在每次修改后触发一次。
    • redux

    • 听说过基于redux的封装吗?

    • 为什么本地开发更改一行代码,浏览器会局部更新那一部分?浏览器怎么知道代码变了?

      这题触及到我的知识盲区了,于是面试官跟我讲解了一下,赞!
      脚手架npm run dev后,会启动一个本地的服务 localhost,它基于socket 连接本地编辑器和浏览器的通信,监听文件系统是否发生改变,当发生改变时webpack 会告诉浏览器代码发生更改,浏览器就会做相应的渲染。这块应该是热更新的知识点。

    • 装饰者模式

    • ts 中 record是做什么的?

      Record构造具有给定类型T的一组属性K的类型。他会将一个类型的所有属性值都映射到另一个类型上并创造一个新的类型.

      实例:

      1. interface EmployeeType {
      2. id: number
      3. fullname: string
      4. role: string
      5. }
      6. let employees: RecordEmployeeType> = {
      7. 0: { id: 1, fullname: "John Doe", role: "Designer" },
      8. 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
      9. 2: { id: 3, fullname: "Sara Duckson", role: "Developer" },
      10. }
      11. // 0: { id: 1, fullname: "John Doe", role: "Designer" },
      12. // 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
      13. // 2: { id: 3, fullname: "Sara Duckson", role: "Developer" }
      14. 复制代码
    • 项目后台搭建为什么选择koa?为什么不是express?

    • 说说个人的亮点


     给大家推荐一个实用面试题库

    1、前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

     

    滴滴 已oc

    1. 感觉面试官问的问题可回答面比较广,所以可以挑自己擅长的领域说~ 而且面试官比较和蔼,让我不要紧张。面试官直接就跟我约了二面的时间。
    2. 复制代码
    • css布局方式

      说了以下四种布局方式,然后以水平垂直居中为例,具体的说了下每种布局方式是如何使用的。

      1. flex
      2. grid
      3. float
      4. position
    • float离开文档流怎么做处理

      我大概说了下清浮动、高度塌陷的不同处理方式,顺便说了下BFC

    • position属性,分别相对谁定位,具体使用场景

    • js 数据类型 Symbol使用场景

    • 类型判断方法

      我说了三种 typeOf、instanceOf、Object.prototype.toString.call() 以及他们各自的优缺点
      面试官接着问了instanceOf 原理,说完继续问了下面两个问题
      Array instanceOf Array == ?(false)
      Object instanceOf Object == ?(true)

    • 数组api,以及在项目使用场景

    • forEach map区别 使用场景

      • forEachmap都可以对数组的进行遍历。
      • forEach返回值为undefined,所以不能进行链式调用,适用于不更改数组的情况;
      • map会返回一个新数组,这个新数组由原数组中的每个元素都调用一次提供的callbackFn函数后的返回值组成。一般用于需要修改数组的情况。
      • 对于数组项是基本数据类型的数组,forEachmap都不修改调用它的原数组本身,但是那个数组可能会被 callbackFn 函数改变; 对于数组项是引用数据类型的数组,用forEachmap都可以改变它的属性值。

      又问:给对象数组中对象的每一项加一个属性,用 forEach 还是 map?
      这里用forEach会更好,直接在原数组上修改即可,如果用map,还要将返回的结果重新赋值给原来的数组变量,语义不好。

    • 手写代码 将对象数组转为对象

      1. const array = [
      2. {
      3. code: 101,
      4. name: '北京',
      5. },
      6. {
      7. code: 102,
      8. name: '石家庄',
      9. },
      10. {
      11. code: 102,
      12. name: '江苏',
      13. children: [{
      14. code: 102,
      15. name: '南京',
      16. },{
      17. code: 102,
      18. name: '连云港',
      19. }]
      20. }
      21. ]
      22. 复制代码

      转换成:

      1. {
      2. '北京':{
      3. code: 101,
      4. name: '北京'
      5. },
      6. '石家庄':{
      7. code: 102
      8. name: '石家庄'
      9. },
      10. '南京':{
      11. code: 102
      12. name: '南京'
      13. },
      14. '连云港':{
      15. code: 102
      16. name: '连云港'
      17. }
      18. }
      19. 复制代码

      实现代码:

      1. function toObj(arr) {
      2. let obj = {};
      3. for(let item of arr) {
      4. if(item['children']!==undefined) {
      5. obj = {...toObj(item['children']),...obj};
      6. }else {
      7. obj[item.name]=item;
      8. }
      9. }
      10. return obj;
      11. }
      12. 复制代码
    • 根据代码看输出 this问题

      1. const obj1 = {
      2. hello: function () {
      3. console.log(this); // obj1
      4. setTimeout(function () {
      5. console.log(this); // window
      6. });
      7. }
      8. }
      9. obj1.hello();
      10. const obj2 = {
      11. hello: function () {
      12. console.log(this); // obj2
      13. setTimeout(() => {
      14. console.log(this); // obj2
      15. });
      16. }
      17. }
      18. obj2.hello()
      19. const obj3 = {
      20. hello: ()=> {
      21. console.log(this); // wondow
      22. setTimeout(() => {
      23. console.log(this); // window
      24. });
      25. }
      26. }
      27. obj3.hello()
      28. 复制代码
    • 闭包 以及项目中的使用

    • 防抖节流

    • vite webpack 了解多少

    • js模块化 commonjs esmodule区别

    • UMD AMD CMD

      • AMD (Asynchronous Module Definition 异步模块定义)
        commonjs是同步加载的,不适用于浏览器环境,所有有了AMD CMD; AMD是异步加载的,模块的加载不影响后面语句的运行。所有依赖这个模块的语句都定义在一个回调函数中,等 加载完之后,这个回调才会运行。AMD 的模块引入由 define 方法来定义
      • CMD (Common Module Definition)
        对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。CMD 推崇依赖就近,AMD 推崇依赖前置。
      • UMD (Universal Module Definition 通用规范模块)
        统一浏览器端(AMD)和非浏览器端(commonjs)的模块化方案。
        1. 先判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块;
        2. 再判断是否支持commonjs(exports是否存在),存在则使用commonjs模块格式
        3. 前两个都不存在,则将模块公开到全局
    • 浏览器缓存 怎么做demo的

      主要针对的是前端静态资源(js css image),大大的减少了请求的次数,提高了网站的性能(两端)

      • 强缓存 设置http响应头
        1. http1.0版本:Expires 具体时间点,客户端时间不准可能会导致误差
        2. http1.1版本:Cache-Control:max-age=xxx 时间偏移量 倒计时
      • 协商缓存
        • Last-Modified 会经常更改的数据,不变则发送304。请求数量不变,请求体积减小
          1. 设置响应头:Last-Modified 文件最近更改时间
          2. 判断请求头:if-modified-since == Last-Modified 发送304
        • etag
          根据文件生成哈希串
          1. 设置响应体:Etag
          2. 判断请求头:if-none-match == Etag 发送304
    • nginx

    • 跨域 jsonp缺点

    • 项目后端做了啥

    • 异步并行/串行
      问 异步事件1、异步事件2是并行还是串行?怎么变为并行?

      1. async() {
      2. await 异步事件1
      3. await 异步事件2
      4. }
      5. 复制代码

      这里我说的是让异步事件不写在await后面,这是一种实现方式。当然还有更好的实现方式,所以面试官问了下一题。

      1. async ()=>{
      2. let result1 = 异步事件1
      3. let result2 = 异步事件2
      4. let res1 = await result1
      5. let res2 = await result2
      6. console.log(res1,res2)
      7. }
      8. 复制代码
    • promose.all 和 promise.allSettled

      先说怎么用promise.all解决上一题吧

      1. async ()=>{
      2. var result = await Promise.all([异步事件1,异步事件2])
      3. console.log(result[0],result[1])
      4. }
      5. 复制代码

      这么写确实可以解决上题的问题,但是在promise.all中如果有一个异步事件出错,那么将会返回一个失败的promise。所以如果异步事件互不依赖的话使用promise.allSettled可能会更好,无论每个异步事件执行成功或失败都会返回一个带有执行结果的promise。 > 想了解更多更多promise.allSettled可以看这里~

      1. async ()=>{
      2. var result = await promise.allSettled([异步事件1,异步事件2])
      3. console.log(result[0],result[1])
      4. }
      5. 复制代码

    最后

     给大家推荐一个实用面试题库

    1、前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

  • 相关阅读:
    Android studio连接MySQL并完成简单的登录注册功能
    Kafka 基础与架构理解
    SQL On Pandas最佳实践
    电脑误删除的文件怎么恢复免费 电脑误删文件导致无法开机怎么办
    优化算法 - 动量法
    【项目问题】Ionic开发移动端app,手把手教你如何打包生成apk
    JavaEE初阶学习:HTTP协议和Tomcat
    复习Day05:链表part01:203.移除链表元素、707.设计链表、206.反转链表、234. 回文链表
    STM32实现六轴姿态测量陀螺仪模块JY61P(标准库与HAL库实现)
    【区分vue2和vue3下的elementUI和elementUI Plus的container组件,介绍如何安装,属性,事件,方法等以及使用案例】
  • 原文地址:https://blog.csdn.net/weixin_42981560/article/details/128044721