likes
comments
collection
share

2024年,龙年大吉吧。裁员,内卷,逆流而上,万字面经梳理

作者站长头像
站长
· 阅读数 12

前言

2024年了,互联网的寒意似乎并没有减退,市场行情看起来还是很不友好样子~

身边的朋友都在说道,今年行情很差,苟住要紧;各位也都被动的越来越卷了,上头让你加班时,再也没有那时到点就下班跑路的气魄了😭

耳闻不如一试,投了几家约了面试,试了下水,看看情况如何🤓

准备

虽说,是想试个水看下外面市场情况,但是该准备的还是要准备的,毕竟机会是留给有准备的人,推荐打算面试的同学还是要多准备准备😀

本篇文章不过多叙述如何准备,着重记录目前市场的面试情况

面试记录

简单介绍一下面试背景:

本人19年毕业,普通本科,计算机专业,4年多前端开发经验,目前投的多是一些中小厂(人员500,1000,1万+规模的都有)

根据面试内容,梳理总结了几个方向

JavaScript

TypeScript

  1. TypeScript的typeinterface区别
    • 说的比较简单,就是一些博客文章里常见的区别,类型别名、类型合并、元祖等
  2. TypeScript的泛型,常用泛型
    • 类比js的函数进行了说明
    • 几个内置工具方法
  3. TypeScript的内置工具方法
    • 记不清那么多,就说了几个常见的 OmitPickPartialRecordtypeofkeyof
  4. 类型安全
  5. 实现一个 type Diff<T,S> = ? 泛型,要求返回两个对象的差异(思考 Equal
    interface A{
       name: string;
       age:number;
    }
    interface B{
       name: string;
       age:number;
       mobile:number;
    }
    // mobile
    

React

  1. react16.8前后class类组件和hooks的区别
    • 说明使用class类组件的原因,维护状态实例,存在的问题
    • 说明fiber架构诞生的历史背景,对已有问题的优化,也就是hooks诞生的背景
  2. 常用hooks
    • 主要介绍了常见的hooks和对应的使用场景
    • 结合fiber作进一步的原理说明
  3. 虚拟DOM / diff算法
    • 这俩可以一起分析,虚拟DOM的诞生背景和作用
    • diff结合虚拟DOM做更新优化等
    • 考虑react/vuediff算法区别
  4. class类组件componentDidMount中进行setState和hooks中useEffect(()=>{setState()},[])进行setState的区别
    • 说了队列异步更新的原理,这里说hooksuseEffect
    • class类组件记不清了
  5. redux的异步中间件实现
    • 看过相关源码,忘了。。,说了sagagenerator
    • 补充:理解中间件的实现方式 => 参数注入,主要是把dispatch作为参数传入,在适当的时机调用
  6. react-router如何监听路由(vue-router
    • 基本原理需要了解,内部实现
  7. 合成事件介绍
    • 围绕react结合fiber控制优化,异步更新分析
  8. react合成事件是如何对应每个事件的
  9. useState状态管理的实现
    • 主要围绕fiber的双缓存说明,以及在hooks中以链表的数据结构管理(围绕链表顺序结构说明)
  10. umi的插件实现机制
    • 没研究过,提到了对webpack的包装以及参数注入
  11. umi项目下的.umi文件的理解
    • 主要围绕预构建思考了路由的动态生成维护和dva数据model的维护
  12. dva的内部实现逻辑
    • 主要围绕rudexredux-saga进行了简要说明,generator的使用
  13. redux的异步中间件实现原理
    • redux-thunk
    • 异步更好的方案是采用 redux-saga,其内部使用了generator函数,可以更好的控制异步操作的执行顺序
  14. react创建context上下文的方式,参数及作用
  15. redux的顶层provider作用及原因

Vue

  1. vue响应式原理
    • 结合vue的初始化过程分析Object.defineProperty()的数据拦截,最好把整个流程说清楚,getter依赖收集DepWacthersetter触发更新通知等
    • vue3proxy说明
  2. 描述了vue2和vue3的区别及实现原理、背景、优化等
  3. vue中如何只让一个对象的第一层为响应式?
    • 提到了 Object.freeze() 方法,追问为什么
  4. vue双向数据绑定原理
    • 结合响应式原理分析,compile解析模板指令和变量替换,绑定对应更新函数,理清ObserverCompileWatcher三者的关系
  5. vue如何做到监听数组的push等操作方法,缺陷原因
    • 主要就是Object.defineProperty()的问题,以及vue内部对数组方法进行了拦截重写
  6. 低代码项目中拖拉拽引出的对于拖拽嵌套实现的一些问题
    • 从原生方面考虑drag相关事件,主要在于对边界条件的判断和处理上
  7. 如何实现组件缓存(keep-alive
  8. xx.vue文件的处理过程,template模板的处理
    • 一开始以为是在问createElement构建虚拟DOM的过程,后来说明是对template字符串内容的处理,主要为正则匹配(标签元素、变量)
    • 思考模板中的变量是如何更新的
    • 聊聊Vue的template编译
  9. vue3的refreactiveunreftoRefs的作用和区别
  10. vue作用域插槽 / react中相似插槽的东西
    • 默认插槽、具名插槽、作用域插槽
    • 延伸思考:react中类似的东西,render props
  11. vue中对于视图层中使用到的变量 a ? b : c,如何更好的做到数据的响应式(b和c只会有一个被使用)

微前端

工程化

  1. Webpack执行过程
    • 围绕webpack执行过程分析,初始化参数、加载插件、使用loader处理非js相关文件、广播事件等
  2. npm install过程
    • 下载到node_modules目录下,更新packge.json文件,并执行安装命令
  3. 组件库、工具库npm包发布相关配置区别
  4. Webpack摘要算法配合服务器实现缓存功能(hash)
  5. loader、plugin简述
  6. loader是什么,它的参数是什么?
  7. Webpack模块加载原理

浏览器

网络

算法

  1. 有效括号,变体(LeetCode 20)
  2. 删除链表的倒数第n个节点(LeetCode 19)
  3. 无重复字符的最长子串(LeetCode 3)

手写题

  1. 节流、防抖

  2. 深拷贝

  3. 实现query查询,支持链式调用

    点击查看代码详情

    实现一个 query,支持链式调用,参数是一个数组

    query(arr)
    .where((item) => item.age > 10)
    .orderBy('age')
    .groupBy('city')
    .execute()
    
    1. where方法,参数用法和 [].filter类似

    2. orderBy(key,desc) 排序,desc为true时为倒序

    3. groupBy(key) 分组,生成二维数组,效果如下

       [
         [
           { name: 'xiao', city: 'hangzhou' },
           { name: 'zhang', city: 'hangzhou' },
         ],
         [
           { name: 'li', city: 'shanghai' }
         ]
       ]
      
    4. execute 方法,只有当该方法执行的时候函数才开始执行

  4. 字符串模板替换

    const data = {
      name: 'banana',
      date: {
        year: '2024'
      }
    }
    const str = '这是一个{{name}}, 今年是{{date.year}}年'
    
  5. 请求并发控制

    点击查看代码详情
    实现一个 scheduler 函数,满足以下要求:
    
    1.  接收一个参数 max 控制最大并发请求量
    2.  执行以下代码依次输出:2314
    
    // -----------------mock一些请求
    const request1 = () =>
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(1);
        }, 1000);
      });
    
    const request2 = () =>
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(2);
        }, 500);
      });
    const request3 = () =>
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(3);
        }, 300);
      });
    const request4 = () =>
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(4);
        }, 400);
      });
    

输出题

  1. react异步更新输出结果

    点击查看代码详情
    class App extends React.Component {
       constructor() {
          super();
          this.state = {
             val: 0,
          };
       }
    
       componentDidMount() {
          this.setState({ val: this.state.val + 1 });
          console.log('1', this.state.val);
    
          this.setState({ val: this.state.val + 1 });
          console.log('2', this.state.val);
    
          setTimeout(() => {
             this.setState({ val: this.state.val + 1 });
             console.log('3', this.state.val);
    
             this.setState({ val: this.state.val + 1 });
             console.log('4', this.state.val);
          }, 0);
       }
    
       render() {
          return null;
       }
    }
    
  2. JS作用域代码输出题

    点击查看代码详情
    var name = "aaa";
    
    const obj = {
       name: "bbb",
       fn1: function () {
          console.log(this.name);
       },
       fn2: () => console.log(this.name),
       fn3: function () {
          return function () {
             console.log(this.name);
          };
       },
       fn4: function () {
          return () => console.log(this.name);
       }
    };
    obj.fn1();
    obj.fn2();
    obj.fn3()();
    obj.fn4()();
    
  3. 异步,宏任务、微任务输出题

    点击查看代码详情
    async function async1() {
       console.log("async1");
       await async2();
       console.log("async2 after");
       await async3();
       console.log("async3 after");
    }
    async function async2() {
       console.log("async2");
    }
    async function async3() {
       console.log("async3");
    }
    console.log("start");
    async1();
    new Promise((resolve) => {
       console.log("promise");
       resolve();
    }).then(() => {
       console.log("promise then");
    });
    setTimeout(() => {
       console.log("setTimeout");
    }, 0);
    console.log("end");
    
  4. 一些基础代码输出题

    点击查看代码详情
    // 第一题:隐式类型转换
    true == 'true'
    
    // 第二题:默认值
    function fn(a = 'abc') {
      console.log('a', a)
    }
    
    fn(null)
    fn(undefined)
    // 第三题:判断改代码是否会卡死页面
    // 1.情况一
    function fn() {
      console.log('abc')
      setTimeout(fn, 0)
    }
    fn()
    // 2.情况二
    function fn() {
      console.log('abc')
      setTimeout(fn(), 0)
    }
    fn()
    
    // 第四题:思考while循环是否可中断
    async function fn() {
      while (true) {
        console.log('开始输出')
        await new Promise(() => {
          console.log('结果')
        })
        console.log('结束输出')
      }
    }
    fn()
    
    // 第五题:执行顺序问题
    // 1
    2**3**2
    // 2
    new new Fn().getName()
    

项目问

项目中的功能和细节一定要做到心中有数,面试官会追着问很多细节,一定要真诚!😄

总结

技术面总的来说还算常规,不少都是常见的八股文,好好准备下还是能应对的;

当然也有一些比较犀利的面试官,问的比较刁钻,如果还只是靠背面经就不行了,你一定是有在这个过程中投入学习的,灵活使用,一定要有自己的理解。

项目非常重要,很多问题是在聊项目细节的过程中提及的,建议抽1-2天时间把项目梳理一下,包括业务流程、项目难点等,最好写下来。

对于手写题,有些方面还有待提高,建议对于常见的手写题还是要多写、多练,特别是promise这类,一定要自己手写几遍。

算法题急不来,常规的典型一定要掌握,什么双指针、动态规划、二分查找等等,没事的时候一天刷1-2题,慢慢就积累上来了,这个只靠死记硬背很难学透,在有一定的数量之后才能引起质变,还是要有那种感觉才行,要不然,看到题,脑子里就空空的,怎么解啊。多刷几题,慢慢的脑子里就有一些解题框架和思路了,方可~

尾声

本文梳理了面试中遇到的一些问题,结合之前自己总结过的文章,已经答复了一部分(已贴出链接的),对于剩余的一些问题,后面会持续输出为面试专题进行归纳(本文会持续更新,补全内容贴上专题链接),对于文中有错误的地方,或者有不同想法的同学,欢迎指出~

要说市场行情寒意,还是能感觉到一些的,目前整个前端市场面试人员很多,有的一个职位投递几十个简历都不算多的,中小厂薪资压的还蛮多的,竞争比较多,卡死在HR谈薪环节的不少。有能力的同学可以多试试大厂😅

总的来说,当下环境还是做好自己,有机会多提升下自己的水平,提高竞争力。加油也好,内卷也罢,能不能熬到下一个风口,并有能力抓住机遇,或许每个人都有自己的答案。

后续打算在这个仓库(JS-banana/interview: 面试不完全指北 (github.com))进行维护,欢迎✨star,提建议,一起进步~