阅读 18850

【从青铜到钻石】3 年创业公司成长经历 && 面试总结

在掘金上当了几年的伸手党,最近也准备输出一些自己的东西。

关于我

首先介绍一下我自己,17 年毕业于一所 211 学校,但是由于大学四年驰骋在召唤师峡谷,毕业时也没有找到一份大厂的工作,随便找了一家创业公司签了三方就去了。好在这家公司也挺给力,我这一呆就是三年,996 当着「全干工程师」,从前端到服务端,从 JavaScript 到 Java,这几年下来都积累了一些经验,不说精通,也算是比较熟悉了。

今年 7 月份的时候,瞅着已经毕业三年,是时候该考虑一下职业生涯的下一站了,开始准备面试的事情。

这里建议大家,每一份工作度需要慎重考虑,不要频繁跳槽。文章后面也会给出我的理由和建议。

在职准备了 2 个月的面试,开始试着投了一些简历,幸运的是都收到了面试邀请,有的公司也拿到了 offer。也尝试投了几家大厂,阿里、字节、快手目前还在流程中。

也已经向 TL 提了离职,最近在工作交接,事情比较少,写个文章记录一下最近的经历。第一次在掘金写文章,希望能有人看。

工作三年

一晃时间就过去了三年,从毕业时候对前端一窍不通到如今在公司独当一面,也算是成长了挺多。嗯,毕业三年的我有4年经验(手动狗头)。

记个流水账吧,大家能够比较直观地感受到我毕业三年以来每个阶段做了什么事:

  • 2017年1月左右。比较早搞定了毕业设计,开始早开始筹备找工作的事。由于是计算机专业毕业,第一想法当然还是找编程相关的工作,就开始了解目前的前端工程师、后端工程师都在做什么,找了几个大厂的 JD 就开始研究,并且听同学说现在牛客上招聘和面经比较多,就去翻了翻牛客。看了牛客之后,TM 被打击了。。。这面经也太难了吧,真的是「面试造火箭」
  • 2017年1月底过年。过年期间回老家同学聚会,刚好也有朋友是计算机专业,建议我可以自学一下前端,找一份前端开发的工作。大二大三的时候帮学长做项目也写过一些前端的代码,想想也挺有趣的,也不纠结了就找前端吧
  • 2017年4月左右。体系化地学习了一下前端相关的知识,发现不对劲,没有实习过的我对于整体的工程经验太欠缺了,而且光是写 Demo 根本无法深入学习,但是由于时间比较少需要看的内容比较多,又只能浅尝则止
  • 2017年5月。投了几份简历,面了几家公司,offer 有,但也都是小公司,对,就是那种只有 20 个人左右的小公司,想想还是放弃了
  • 2017年6月。机缘巧合在 V2ex 上了解到一个创业公司,人不多,但是待遇还不错,就去试了试。面试官很 Nice,聊得挺不错,虽然我没有实习经验也没关系,他觉得应届生基础好,学习能力强就没问题(😁 我信了。。)
  • 2017年6月。签了三方,毕业旅行去了。美滋滋。
  • 2017年7月。从学校毕业,进入这家创业公司开始了我的前端生涯
  • 2017年7月 - 12月。因为这家创业公司已经有一定规模了,除我之外还有 3 个前端,所以我刚来之后活还比较轻,主要就是写一些无关经验的后台页面和 toC 的移动端页面,主要技术栈是 Vue。Vue 也是我来了公司之后才开始学的,看了一遍文档之后就直接开干,啥不会的就 CV 大法,还不会的就厚脸皮请教公司的前辈,就这样过了差不多半年吧
  • 2018年1月-6月。TL 看我已经逐渐掌握了前端技术栈的开发,也开始给我安排一些比较有挑战性的活,负责一些日活比较高的项目日常维护和迭代。在这半年时间里,更多时间还是在跟业务,没有太多技术上的思考。当然,我的手还是非常快的,5天工作量的页面我3天就能搞定,而且提测基本 0 bug。当然,这里的手快不是敲键盘快,更多的是对于项目的理解和功能模块的拆分,以及页面组件、模块的设计,保证复用度。这里我的建议是:拿到一个业务需求,先理解透彻再动手编码。理解包括对业务的理解和对需求的理解,将产品给到的 PRD 进行拆解分析,派出优先级和每项的排期,这样对于整体项目都能有一个把控
  • 2018年7月-12月。业务已经稳定,团队也有了差不多差不多 8 个人,开始接手一些团队基础设施建设的事情,比如统一脚手架、统一 UI 组件库以及统一技术栈的前期工作
  • 2019年1月-6月。和 TL 一起推动统一了 React 作为前端统一技术栈,刚好拿到一个比较重要的业务,借这个项目沉淀了项目脚手架(包括中后台和 mobile),以及UI 组件库(基于 antd 进行定制、封装),在 3 月份的时候我也顺利完成晋升(其实就是调了薪资)。从 18 年 7 月到 19 年 6 月这一年时间真的痛并快乐着,每天肝到最后一个下班,之前没接触过前端工程化体系,就没日没夜地学习。而且推动技术栈统一其实是一个很艰难的事情,这得拿出足够的理由和证据让团队成员信服,并且得要有足够的技术支撑(脚手架、组件库、工程化能力、知识体系支撑),幸好 TL 也一直很支持这个事情,总算在肝了一年后顺利建设了目前团队的技术底座(当然还是比较 low 的,后面也一直在迭代
  • 2019年7月-12月。基本做的就是脚手架、组件库、工程化的完善的,以及 CI/CD 的一些事情
  • 2020年1月-2020年6月。团队的开发模式基本已经成型,只需要投入 2人日/周基本就可以。我们也开始沉淀团队统一的埋点、监控方案,打造了统一的前端埋点管理系统、前端埋点工具、前端监控平台
  • 2020年7月。虽然可能你觉得我三年来干了很多事情,但是如果深入细节看,很多事情都是小打小闹不成体系,业务量大了之后未必可以 cover。所以决定再次寻找自己新的定位,进入一个大厂,体系化地了解整个前端研发生命周期中大厂是如何思考和沉淀的

工作三年,学到很多。很多人可能会说:还是因为这家创业公司给力而且 TL 比较给力,所以可以待到三年。是的,这话没毛病,我也很感谢我的 TL,感谢公司给了这样一个平台让我成长。

但是,我想说的是,除了外界客观因素之外,自身的主观因素也很重要。在上面的个人经历中,我写出来的可能都是让你感觉很爽的事情,很多不爽的事情我没写出来而已。。

  • 经常肝到半夜
  • 被 TL 批评过,也经常怀疑过自我
  • 暗地里说过业务方(这人也太xx了,还天天摸鱼)、骂过公司(公司也太xx了,迟早完蛋)
  • 无数次想要离职的经历,懂的人都懂,随时都想砸了电脑走人
  • ...

太多了,如果要写,我可以写出 100 条「我为什么曾经无数次想要离职」。

人生就是这么有意思,无数次想要离职都没走,这次确是主动想要换个环境,并且需要放弃一些东西。

复习准备

掘金上关于面试的文章很多,这也是社区一个现状,所以就挑了几篇个人觉得比较好的着重看了一下:

以上文章个人觉得就够了,能花时间把这些知识啃下来,一般面试就没什么问题了。

简历准备

简历真的非常重要,校招的时候就有这样的感觉,那时候有实习经历和没实习经历简直就是一个天一个地。这次也准备认真准备一下自己的简历。

对于简历,个人认为大厂面试官和 HR 最看重的是两点:

  • 项目经历:做了什么
  • 工作经历:稳定性

这里就不展开说了,社区里也很多优秀的文章。在这个过程中,我主要参考了以下几篇文章,推荐一下:

面试题整理

这里整理一下我这段时间面试遇到的面试题,按类型分一下,这里只整理了我记录的问题,来不及写答案。。

JavaScript

1. 说说 JavaScript 的数据类型

算是面试官拿一个简单的题给面试者热热身找找感觉吧。

  • 基本数据类型:String、Boolean、Number、Symbol、null、undefined
  • 引用数据类型:Object,如果要细分的话有 Object、Array、Date、RegExp 和 Function

2. 基本数据类型和引用数据类型有什么区别?

很自然地就引出这个题,基本数据类型在被创建时,在栈上给其划分一块内存,将数值直接存储在栈上; 引用数据类型在被创建时,首先在栈上创建一个引用,而对象的具体内容都存储在堆内存上,然后由栈上面的引用指向堆中对象的地址。

3. 那基本数据类型和引用数据类型拷贝的时候有什么区别?

由于存储的位置不一样,直接拷贝的时候就会有两种情况:拷贝了值和拷贝了引用,也就是我们常说的深浅拷贝。

对于基本数据类型而言,没有深浅拷贝的概念,都是在栈上新开辟了一块内存给新的值。而对于引用数据类型而言,区别简单来说就是会不会共享堆内存里的值。具体不说了,文章很多,随便看两篇基本都没啥问题。

目前 JavaScript 的 API 中,哪些是浅拷贝,哪些是深拷贝?

可以看看这篇文章,虽然文章里有一些小问题,不影响整体阅读

4. 如何实现一个深拷贝?

无非就是 JSON.stringify递归 两种方法,大概说说思路就 OK

5. 通过 JSON.stringify 的方式实现深拷贝,会有什么问题?

如果值是 undefinedfunction 等,在转换的时候会丢失,所以还是要比较谨慎使用 JSON.stringify 来做深拷贝

6. 通过递归的方式实现深拷贝,会有什么问题?

循环引用和重复引用

数据类型和深浅拷贝的问题问到这里基本差不多了。这里说个小技巧:如果面试官问了第一题,面试官应该心里已经有打算问你深浅拷贝的问题,如果你比较熟悉,也可以尝试主动点往这方面引。

7. 数组去重的方式有哪些(手写)

花里胡哨的也就那几种,主要考察对 JavaScript API 是否熟悉,我写了两种:SetHash,面试官也没有多问。

Hash:

function unique(arr = []) {
  if (arr.length === 0 || arr.length === 1) {
    return arr;
  }
  const newArray = [];
  const hash = {};
  for (let i = 0; i < arr.length; i++) {
    if (!hash[arr[i]]) {
      hash[arr[i]] = 1;
      newArray.push(arr[i]);
    }
  }
  return newArray;
}
复制代码

Set:

function unique(arr = []) {
  if (arr.length === 0 || arr.length === 1) {
    return arr;
  }
  return [...new Set(arr)];
}
复制代码

8. 找出数组中最大的数(手写)

我就只写了一种

function getArrayMax(arr = []) {
  if (!arr.length) return;
  if (arr.length === 1) {
    return arr[0];
  }
  return Math.max(...arr);
}
复制代码

9. 说一下事件循环的理解

宏任务微任务那些,随便搜都是,只推荐一篇经典文章:Tasks, microtasks, queues and schedules

10. 快排是如何实现的,讲一下思路和复杂度

放两张图,感受一下,更多的动画可以看 visualgo.net/zh/sorting

img

11. 如何实现一个观察者模式(手写)

12. 如何实现一个单例模式(手写)

13. 如何解析一个 URL,获取 query 和 hash 的参数(手写)

14. TypeScript 和 JavaScript 最大的区别在哪

CSS

1. flex 如何实现九宫格

width,变 flex-wrap

2. 除了 flex 之外,还能如何实现九宫格

比较老的 float,比较新的 grid,然后展开说下 grid

3. flex: 1 是什么意思

我就说了一下 flex: 1 的作用,然后说了一下 flex 其实有三个值,分别简单说了一下各自的作用,就过了

4. 移动端适配怎么做的,rem 原理是什么,vw 有没有了解

细说移动端 经典的REM布局 与 新秀VW布局

5. 移动端 1px 如何解决

React/Vue

1. 看你的简历,Vue 和 React 都写的比较多,可以说说 Vue 和 React 的区别吗?

通过自己的理解,从编译、生命周期、数据流、核心思想等方向都介绍了一下吧,这个问题还是需要认真准备一下,我说的时候感觉有点乱,回头我看看写一篇文章专门回答一下这个问题吧

2. 新项目的技术选型,你会从哪些方面来考虑选用 Vue 还是 React?

这个问题我听到就感觉比较谨慎,因为本身就是在创业公司,面临过很多次的技术选型。从 jQueryVueReact,我们也经历了技术栈的更新换代。我们当时在考虑技术选型的时候,我们考虑的不是一个新项目,而是一个未来 2 - 3 年甚至更久的一个长远技术选型,主要看了一下 ReactVue 的一个整体生态和完整度,当然这也包括社区的活跃度。因为我们并没有太多人力做一些框架底层的工作以及一些生态周边配套解决方案,更多的时候是拿一些现有的解决方案来解决我们的业务问题。

我在回答这个问题的时候,更多的时候是通过本身的业务出发回答的,没有过多地回答 ReactVue 框架上的区别对技术选型带来的影响。

3. 说说对虚拟 DOM 的理解

虚拟 DOM 本质上是一个真实 DOM 的抽象 JavaScript 对象。然后展开说了一下虚拟 DOM 的好处,操作 DOM 简单、轻量、跨平台,我特别提了一下跨平台,Vue 2.x 之后引入的虚拟 DOM,也有一部分是为了解决未来跨平台的问题,后来也结合 WEEX 了。

4. 讲讲 React 的生命周期

这个没啥好说的,根据自己的理解说一下那几个生命周期了。也说了一下即将废弃的生命周期以及为什么废弃,就过了。

5. React 函数式组件和类组件有什么区别

6. React 的 diff 和 Vue 的有什么区别

单向双向的区别

7. 列表中的 key 有什么作用

VirtualDOM diff

8. 说说 React Hooks 的理解,它有什么优点

一篇看懂 React Hooks

9. React Hooks 不能出现在条件判断语句中

可以确保每次渲染组件时都以相同的顺序调用 Hook

10. 什么是高阶组件?

  • 高阶组件(HOC)应该是无副作用的纯函数,且不应该修改原组件

  • 高阶组件(HOC)不关心你传递的数据(props)是什么,并且被包装组件不关心数据来源

  • 高阶组件(HOC)接收到的 props 应该透传给被包装组件

11. React 的高阶组件和 Vue 的 mixins 是一个类型的东西吗?Vue 中是否可以实现类似 React 的高阶组件

高阶组件本质就是高阶函数,React 的组件是一个纯粹的函数,所以高阶函数对React来说非常简单。

Vue 更像是高度封装的函数,在更高的层面 Vue能够让你轻松的完成一些事情,但与高度的封装相对的就是损失一定的灵活,你需要按照一定规则才能使系统更好的运行。

12. Vue 的双向绑定是如何实现的

数据劫持和发布订阅

13. Vue 如何收集依赖

14. Vue 的父子组件挂载顺序是怎么样的

created -> 子created -> 子mounted -> 父mounted

15. Vue 的 computed 和 watch 是怎么实现的

16. Vue 的 template 是如何编译的

vue-loader 里有然后专门处理 templateloader,最终本质上还是 createElement

17. Vue 3.0 和 2.x 有什么区别

definePropertyproxy,更开放的 APIts 等等...

18. defineProperty 有什么缺点,为什么 Vue 3.0 之后改用 proxy

数组、对象的监听

19. 我不是前端,你如何向我介绍 Vue,让我能够尽可能多的了解它

工程化

1. webpack 和 rollup 的区别

webpack 适用于大型复杂的前端站点构建,rollup 适用于基础库的打包

2. 说说 webpack 的 loader 和 plugin

loader 解析模块,plugin 扩展功能

3. esbuild 有没有了解

下一代构建工具,是使用 go编写的,未来的趋势会更多使用非 JavaScript 语言来编写前端工具,优点是快。

4. CommonJS 和 ESM 有什么区别

这个就不展开说了,找两篇关于 JavaScript 模块的文章看看就 OK

5. vite 和 snowpack 有了解吗,unbundle 有什么好处

个人理解会是未来构建工具的一种趋势,在构建速度/热更新速度上都比目前 webpack 的方案快非常多,大幅度提高前端开发效率。

6. webpack 的热更新原理大概介绍一下

本地起服务,通过文件内容 hash 来判断是否更新,客户端收到更新消息后会取拉取最新代码进行更新

7. vue-loader 做了哪些事情

webpack 用于处理 .vue 文件的 loader,解析代码,分别处理其中的 template/style/script...

8. tree sharking 是什么

ESM,代码体积优化,CommonJS 不支持

9. webpack4 相对于之前做了哪些优化

10. 项目中,你使用 webpack 做了哪些优化

  1. 使用 happypack 加速构建
  2. 通过 analyze 插件分析构建产物大小,优化体积
  3. chunk
  4. dll
  5. ...

11. 如何发布一个 npm 包,如何发布一个 beta 包,如何修改一个正式包为 beta 包

12. npm 包的版本号是如何规范的

参考 semver.org/lang/zh-CN/,这里提了一下 break change 以及不规范的 npm 版本号会带来什么影响

13. DefinePlugin 的作用是什么

定义全局变量,可以用于不同环境的代码删除

14. 你们团队的项目脚手架是如何实现的

使用 Yeoman 开发的脚手架,介绍了一下 Yeoman 的能力,以及为什么要用它而不是直接用现成的 cravue-cli

15. Babel 的原理是什么

编译器。分为三个阶段:

  • parse:词法分析 语法分析

  • transform:转换ast

  • generate:生成代码

后端

1. Koa 和 Express 有什么区别

  • 异步:callbackpromise
  • 中间件:线性模型和洋葱模型

2. 说说 Koa 的中间件原理

洋葱模型示意图

3. 常用的 Node API 有哪些

4. SSR 是如何实现的

img

5. serverless 有了解吗

6. 说说 node 的执行机制(单线程)

7. 为什么说 node 是高性能的

8. node 为什么支持高并发

  • 执行速度快:运行在 Chrome V8 引擎上
  • 异步:libuv 事件循环
  • 适用 I/O 密集的网络应用开发:解决网络应用开发 I/O 的性能瓶颈

9. 说说 MVC 的思想

Model–view–controller

10. 说说 ORM 的优点

本质上是对 SQL 语句的一种抽象,方便(语句清晰),安全(一定程度防注入)

11. MySQL 和 MongoDB 有什么区别

关系型数据库和非关系数据库

12. 依赖注入是什么

网络

1. 从输入 URL 到页面渲染,其中发生了什么

这个问题真的很大,可以说很多东西,因为在问这个问题之前面试官在聊网络,所以这个问题我也就回答了网络方面相关的,至于浏览器渲染相关的我就随便带了一下就过了

2. HTTP 和 HTTPS 有什么区别

从安全的角度说呗

3. 说说 HTTP 的状态码

随便说了几个常见的状态码,一般面试官问这个,其实是准备找几个常见的状态码问你具体什么意思,所以你就说自己比较了解的几个就好了,如果完全没了解过的,就别给自己挖坑了

4. 304 状态码是什么意思

缓存

5. 浏览器的三级缓存策略了解吗

  1. 先在内存中查找,如果有就加载
  2. 如果内存中不存在,则在硬盘中查找,如果有就加载
  3. 如果硬盘中也没有,那么就进行网络请求
  4. 请求获取的资源缓存到硬盘和内存

6. 说说浏览器的缓存,强缓存是什么

7. websocket 是怎么建立链接的

8. HTTPS 是如何保证网络安全的

9. HTTP 如何实现长连接

keep-alive

算法(手写)

1. 回形打印矩阵

2. 找出最长子字符串

3. 数组中的第 K 个最大元素

4. 用 JavaScript 实现一个链表

5. 从上到下打印二叉树

其它

1. 介绍一个你觉得比较有亮点的项目

说了一个从 0 到 1 的项目,并且在这个项目中,我沉淀了一套目前公司统一使用的脚手架工具以及一个 UI 组件库。由于是 0 到 1 的项目,项目周期中遇到了一些协作的问题,我也主动承担了一些 PM 的角色,去推动项目正常运行,保证了项目正常上线,获得业务上下游团队的好评。

2. 在创业公司,一个前端项目的生命周期是怎么样的

在网上也看到了一些大厂的工作流程,相比来说,我们这边的流程相对来说,大的骨干都有,但是小的地方就显得不够规范。比如 Code Review、发布管控、灰度回滚能力等,目前在我们的研发生命周期中,这些能力都只是 “能用” 的阶段,目前我们也在加强规范建设。

3. 在团队中,你是如何制定编码规范的,如何推动规范落地的

根据目前业界常用的编码规范,制定了编码规范,以及一套 ESLint/StyleLint/CommitLintd 静态检查工具,当然还有 Prettier ,然后就是推广大家用,用的过程中再迭代这套编码规范。

4. 你还有什么问题想问我的

不要频繁跳槽

文章开始的时候有提到「不要频繁跳槽」,这里谈谈个人的看法。

对于面试官和 HR 来说,「频繁跳槽」意味着两点:

  1. 你的稳定性不足,得承担给你发了 offer 之后你来到公司过了一段时间又跑路的风险,所以会是减分项
  2. 你没有足够的沉淀,技术和业务的沉淀是要时间的,对业务有深入的理解才能思考如何通过技术手段来解决业务上的问题

对于个人来说,「频繁跳槽」意味着:

  1. 一直在准备面试,一直在刷题,没有一个专项学习的时间段
  2. 技术栈一直在变,一直在适应,没法更深入的理解
  3. 对业务不理解,对团队不熟悉,恶性循环,又想跳槽

总结

这篇文章主要还是记录一下自己这段时间以来的一些经历,希望对大家能有帮助。之后也会输出一些「全干工程师」的技术文章在这里,感兴趣的朋友可以先关注。

当然,如果有空,我也会将我对上面面试题的回答都整理一下,发在社区上。

最近看大家都在流行公众号,我也建了一个:full_stack_interview,感兴趣的朋友可以关注一下,之后文章会优先发表在公众号上,争取做一个高质量的公众号。

也可以加我微信:xiaolu950621 交流。