阅读 11148

“寒冬中”三年前端社招面试经验

前言:16 年毕业的渣本程序员,毕业后一直在上海某公司工作,小组氛围以及同事都非常 nice,但是业务线发展不好,年后回来后被砍了,不想内部转岗到其他部门,所以加入了找工作的大潮。这次的找工作经历对我来说很重要,它让我在准备的过程中突然对很多技术问题有所觉悟,想记录一下这次的经验。

基本都是在 Boss 直聘加内推 ( 内推真的会比较靠谱,可以提前知道消息并且避免去边缘部门 ) 上投的,也没投几家,一开始就是奔着大厂去的,现在的公司不算大厂并且是按照业务线分组的,所以我们小组几个人开发一款产品,前端也一直只有我一个人在负责,所以一直想去大厂试试。

大概面了 xxxxxxxxxxx(面试公司已删,去哪家都是搬砖,差不了多少的),也是从一开始面试讲话都有点不太自信,到后面有底气去跟面试官扯皮子了,心态变化了很多。

忘了准备多久,目前的公司其实不加班,但是我都是晚上留到八九点,看书刷题,之前一直想看的剑指 offer 居然也看完了,不懂的会跟着刷,重新开了 LeetCode 中国区的账户,刷了 10% 的题目,达到了一开始是对算法没有思路到不再害怕算法知道可以从哪里入手的水平,很多公司面试算法其实没要求那么高特别是前端,不过也要对自己要求高一点。

因为刚刚旅游了一趟回来,对具体哪家公司的面试题目不太分得清了,以下都是我的面试内容,希望能对其他人有所帮助:

css

1. 三栏布局

  • float
  • bfc (set middle area overflow is hidden)
  • position: absolute
  • 双飞翼布局
  • flex
  • table

2. 垂直居中

个人感觉这个问很多,我一般就是答以下几种:

  • line-height: height 有被问到该值是不是等于高度设置的值,这个没有答好,回来测试发现是跟盒模型相关的,需要是 computed height
  • absolute + transform 居中为什么要使用 transform(为什么不使用marginLeft / Top),这是一道重绘重排的问题。
  • flex + align-items: center 我会对 flex 容器以及 flex 项目的每个 css 属性都了解一遍,并且写了一些小 demo。

3. 盒模型

4. BFC

  • 概念
  • 如何触发
  • 怎么应用

5. CSS 预处理器

一般回答 变量 / 嵌套 / 自动前缀 / 条件语句 / 循环语句

我是一直很欣赏张鑫旭大神对 CSS 研究到非常透彻的境界,但是总结下来,对 CSS 一般不会考得很深,业界对 CSS 的专注度其实不够,包括我个人也是没投入很多时间精力在 CSS 上,如果有更深入的理解当然是更好的。

JS

1. 原型

其实之前刚毕业的时候就在啃高级程序设计,三年后还是在考这个点。

  • 闭包 / 作用域 / this 指向
  • 实现 继承
  • es5 实现 class
  • es5 实现 new

2. var let const

let/const 也存在变量声明提升,只是没有初始化分配内存。 一个变量有三个操作,声明(提到作用域顶部),初始化(赋默认值),赋值(继续赋值)。

  • var 是一开始变量声明提升,然后初始化成 undefined,代码执行到那行的时候赋值。
  • let 是一开始变量声明提升,然后没有初始化分配内存,代码执行到那行初始化,之后对变量继续操作是赋值。因为没有初始化分配内存,所以会报错,这是暂时性死区。
  • const 是只有声明和初始化,没有赋值操作,所以不可变。

const 只是保证了指向的内存地址不变,而不是内部数据结构不变。确保不会被其他类型的值所替代。

3. 实现 promise

面 tx 的时候有让我手写实现 promise,因为有看过一点 bluebird 的源码,所以对我来说还好。写了一半就让我停下来,我一般会边写边讲解,一上来先把框架搭好,例如

class Promise {
    constructor(executor) {
        // 设置属性 status value resolveCbs rejectCbs
    }
    then(onResolved, onRejected) {}
    catch (cb) {
        return this.then(null, cb)
    }
}
复制代码

然后再慢慢填充,这种做法会一上来让人感觉你是有思路的,而且了解 promise 的语法。

4. promise 链式

例如 promises = [],实现必须上一个异步完成后再去跑下一个任务。我是写出两种方案:

// 1.
const template = Promise.resolve();
promises.forEach((p) => {
    template = template.then(p)
})
// 2. 使用 await 
复制代码

个人感觉对 promise、async/await 都问比较多,包括比较火的问打印顺序那种题还有捕获异常的问题我也遇到过,只要对语法非常熟悉加上稍微了解实现细节都是没问题。

5. 实现 bind

6. 实现事件系统 eventEmitter

跟 promise class 一样,先搭建一个框架:

class EventEmitter {
    constructor() {
        this.events = {}
    }
    emit (eventName, args) {}
    on (eventName, callback) {}
    off (eventName, callback?) {}
}
复制代码

之前有写过事件系统,但是没有考虑 once 之类的 method,也是面试官说了需求再一点点补充的。

7. 手写 Proxy / Object.defineProperty

8. 事件委托

9. Event Loop

JS 执行是单线程的,它是基于事件循环的。事件循环大致分为以下几个步骤:

(1)所有同步任务都在主线程上执行,形成一个执行栈。

(2)主线程之外,还存在一个"任务队列"。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

event loop 基本每次都会被问到,一般就是说微任务、宏任务,怎么样的运行过程,以上是比较书面一点的回答,我自己也没记得。

10. Webpack

  • loader plugin 的区别,一开始被问到还有点惊讶,不同作用的功能被问到一起。
  • tree-shaking 的工作原理
  • code splitting用的是什么插件
  • 如何提高 webpack 构件速度的
    • 利用 DllPlugin 预编译资源模块
    • 使用 Happypack 加速代码构建

我写过很多小项目,所以配过很多次 webpack,从 V2 到 V4,不过 webpack 一般没有问很多。

11. 前端性能提升

一般我会分为以下几个方面来回答,一般会引申到网络、缓存方面的问题:

server:

  • 使用 cdn
  • 减少不必要的数据返回
  • 使用 gzip
  • 缓存 (etag / expires ...)

content:

  • 减少 http 请求 (css sprites / inline image)
  • 不同资源放在不同域下 (http1.1)
  • 延迟加载 / 延迟执行(立即下载,延迟执行[before DOMContentLoaded]defer) / 预加载(preload)
    • async,该布尔属性指示浏览器是否在允许的情况下异步执行该脚本。该属性对于内联脚本无作用 (即没有 src 属性的脚本)。
    • defer,这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发DOMContentLoaded事件前执行。
  • 精简 HTML 结构
  • 压缩资源

css:

  • in head
  • 较少的层级(之前被问到过是否有统计过层级多与少对性能的实质影响,实际上我是没有做过此类研究,所以知道结论而不懂过程还是欠缺的)

js:

  • before
  • 减少 dom 访问(在 body 内放置的 JS 代码是否可以访问到 body 标签)

webpack:

  • tree shaking 去除没有使用的代码
  • 提取公共包,有被问到
  • 拆分模块,按需加载
  • 优化图片,使用 base64 代替小图
  • file name with hash (etag)

12. Vue

因为我是写 Vue 居多,所以简历上只写了 Vue 而没有 react 等其他框架,一般都是被问到 Vue。

  • 父子组件通信
  • 生命周期
  • 数据响应(数据劫持) 数据响应的实现由两部分构成: 观察者( watcher )依赖收集器( Dep ),其核心是 defineProperty这个方法,它重写属性的 getset 方法,从而完成监听数据的改变。一般会要求从解析到收集依赖到通知一套工作原理比较熟悉。我是大概理解,跟着读了一些源码,但是还是没有讲很清楚,遗憾没有表现好。
  • 虚拟 dom、dom diff
  • nextTick

JS 肯定是重点考察的部分,对象、继承方面只要读透高程再写几个 demo 掌握细节,es6 我是一直翻阮一峰写的 ECMAScript 6 入门,Vue 的话首先把官网的内容掌握了,然后再去读一些博客或者直接上源码也是可以的。

HTTP

1. 跨域

基本都被问同源策略以及引申到跨域来,一般我会说 CORS 以及 jsonp,CORS 会从简单请求跟非简单请求区分开,再讲 options 请求的意义。

2. HTTP 报文

请求行 + 头部信息 + 空白行 + body 有被问到说空白行的意义,我一直以为就是纯粹来标识 headers 的结束,但是面试官说不止这个功能,我后面看了HTTP 权威指南 也没有找到,Stack Overflow 也没找到。。。希望有人知道可以跟我说一下。不过有可能是我听错了题目,毕竟是电话面试。

3. cookie session

一般会问两者的差别,以及引申到 sessionStorage, localStorage, cookie 区别

4. 从输入 URL 到页面加载全过程

一般我会答链接的大部分步骤,按照理解来,这里面我被问到的点有:

  • 缓存,分为强缓存、协议缓存,一般会问到 304 的表现,以及再引申到 301 302 的区别,我会再说 307 的区别。
  • 三次握手
  • HTTPS 的工作原理
  • CDN 的工作原理,以及刷新缓存的原理。
  • 浏览器渲染的步骤
  • 重绘重排的概念,以及最佳实践。一直都知道应该用 transform 代替 margin,但是一被问原理,就不太清楚,查了资料是对 translate3d 的元素进行 GPU 加速。
  • 会因为 JS 是单线程而问到阻塞的问题,引申到 async defer 等属性。
  • status code 有哪些,我们是严格按照 restful 的规范来设计接口,所以这个问题我一直觉得很简单,但是被问到不少次。我记得趣头条的笔试就有,我会把用过的按照 2xx(200, 201, 204, 206) 3xx(301, 302, 304, 307) 4xx(400, 401, 403, 405) 5xx(500, 502, 504) 来分类,我偶尔写写 rails,所以对对应的名词都比较熟悉 贴一篇 list of rails status codes
  • DNS 解析过程

5. xss,csrf

  • xss 注入攻击
    • 转义
  • csrf (cross site request forgery)
    • Get 请求无副作用
    • cookie httponly
    • cors (origin not *)

我是通过看 这篇文章 对安全有更多了解的,推荐一下。

6. sse( server sent event)

因为写过一个 sse 相关的插件,所以被问到过,是如何使用以及 EventSource 的 API。

感觉前端对网络、安全方面要求不是很高,没被问过 HTTP2 或者长连接更多内容,之前看脉脉上一个后端被问从浏览器里访问一个地址,从网络的 tcp/ip 协议、聊到操作系统 io、内存管理、进程管理和文件管理,再聊到负载均衡、限流算法、分布式事务,相比之下前端真的简单很多,不过知识储备多肯定是有用的。

算法

算法一般考得不难,不过基本每一次面试都会考到,我记得被考到算法题目有:

  • 层次遍历一棵二叉树 (这是唯一一道剑指 offer 上的题目了,最简单的 😂 )
  • 字符串中找出最长最多重复的子串

想列举发现很多已经忘了,感觉很少会直接出现剑指 offer 的题目,也不会直接问某排序算法怎么写,这是我个人的体验,仅供参考。刷题还是很有用的。

Git

  • 基本操作

  • git rebase vs git merge

    • git merge
      • 记录下合并动作 很多时候这种合并动作是垃圾信息
      • 不会修改原 commit ID
      • 冲突只解决一次
      • 分支看着不大整洁,但是能看出合并的先后顺序
      • 记录了真实的 commit 情况,包括每个分支的详情
    • git rebase
      • 改变当前分支 branch out 的位置
      • 得到更简洁的项目历史
      • 每个 commit 都需要解决冲突
      • 修改所有 commit ID

    回答时候没有答出很多,这是后面总结,深刻发现日常做总结的必要性,一直觉得自己是了解的,等到总结时候才发现有一些 point 还是不清楚的。

  • 修改 commit message

没有问很深,只是基础操作多一点。如果日常是使用 git 开发,一般比较轻松应对。


总结:以上都是我的面试题目,并非齐全的面试准备内容,我也遗忘了很多题目,再不写下来估计忘更多了。一般都是问具体的技术问题加上项目经历,因为我这边做的事情是技术多于业务,目前只有我一个人负责全部的前端内容,所以对每个项目都非常熟悉,建议对写在简历上的项目都知根知底,避免出现被问到时候含糊不清的尴尬场景。

至于标题为什么“寒冬”加上双引号,我觉得对寒冬的解释在于个人而非完全是大环境影响,感觉每个公司都挺缺人的,挂了鹅厂后 HR 给我看了面试评价以及又帮我投了其他部门,不过是我在旅游期间联系我的,已经接了 offer 就没继续面了。

我这次找工作的体会大致如此,没有很糟糕没有很愉快,过程中压力也是比较大的,但是换工作就是如此的啊,从舒适区跳出来太难了,希望能通过我的经历给人一点帮助吧。


这算是我写的第一篇博客,有收到一些关注,只是因为在 juejin 看了一些面经所以想也写一篇而已,其实是没有写博客的习惯,所以关注的可以取关。。。交流一些前端技术是欢迎的。

关注下面的标签,发现更多相似文章
评论