断更了一段时间,时间过得真快啊~已经入职新公司好几个月了,博客不能落下,把之前的面试总结分享一下~坐标杭州,让我们一起看看三年前端都面了些啥吧

我个人的习惯是在开始面试前先把知识点粗略的过一遍,笔试题只做最经典的那些题目(比如有效的括号,还有根据每项的 parent_id , 生成具体树形结构的对象)全都记录下来。每次面试遇到的问题再补充到文档里。面多了也就能知道哪些问题是高频问题,这类问题要完全把细节搞懂,面试的时候才能自然流畅的完整回答,不怕刨根问底。基础问题一般都在最前,这关过了就能到项目相关的部分了。
项目相关的也就是最最最重要的部分!面试官基本会围绕一些你在项目经历中的关键词进行提问,比如:性能优化、大文件上传、虚拟列表等... 这个部分针对个人的项目来准备,主要就是把每个项目拆出几个难点,遇到的难点和解决方案分别是什么?可以幻想在自问自答,你的回答是否完美?有没有更好的优化方案你没有提到的?为什么选择这个方案等等(最简单的方法,问 AI)。把每个类型的文档分类好,在面试前复习就看这些,同时别忘了录音录像,面试完总结,再继续补充文档!将来换工作也可以继续温习。
接下来分享一些高频的面试题~
- 选择器优先级
-
在属性后面使用!important 会覆盖页面内任何位置定义的元素样式。
-
作为 style 属性写在元素内的样式 如
style="color: green",权值为1000 -
id 选择器 如
#app,权值为0100 -
类、伪类、属性选择器 如
.foo, :first-child, div[class="foo"],权值为0010 -
标签、伪元素选择器,如
span,div::first-line,权值为0001 -
通配符、子类、兄弟选择器,如
*, >, +,权值为0000 -
浏览器自定义或继承(没有权值)
可继承的样式: font-size font-family color, UL LI DL DD DT;
不可继承的样式:border padding margin width height ;
-
盒子模型的宽度计算
CSS 中任何元素都可以看成是一个盒子,而一个盒子是由 4 部分组成的:内容 (content)、内边距 (padding)、边框 (border) 和外边距 (margin)。
默认 box-sizing : content-box 是 W3C 盒子模型
box-sizing: border-box 是 IE 盒子模型
IE 盒子模型:包括 width + border + padding (不包括 margin)
盒模型的组成:由里向外内容 (content)、填充 (padding), 边框 (border),边界 (margin)
区 别:在标准的盒子模型中,width 指 content 部分的宽度;IE 的 content 部分把 border 和 padding 计算了进去;
-
文档流
将窗体自上而下分成一行一行,并在每行中按从左至右依次排放元素,称为文档流,也称为普通流。
这个应该不难理解,HTML 中全部元素都是盒模型,盒模型占用一定的空间,依次排放在 HTML 中,形成了文档流。
什么是脱离文档流
元素脱离文档流之后,将不再在文档流中占据空间,而是处于浮动状态(可以理解为漂浮在文档流的上方)。
脱离文档流的元素的定位基于正常的文档流,当一个元素脱离文档流后,依然在文档流中的其他元素将忽略该元素并填补其原先的空间。
如何脱离文档流
○ float
使用 float 脱离文档流时,其他盒子会无视这个元素,但其他盒子内的文本依然会为这个元素让出位置,环绕在该元素的周围。
○ absolute
absolute 称为绝对定位,觉得应该称为相对定位,
因为使用 absolute 脱离文档流后的元素,是相对于该元素的父类(及以上,如果直系父类元素不满足条件则继续向上查询)元素进行定位的,
并且这个父类元素的 position 必须是非 static 定位的(static 是默认定位方式)。
○ fixed
完全脱离文档流,相对于浏览器窗口进行定位。(相对于浏览器窗口就是相对于 html)。 -
BFC
什么是 BFC(规定内部块级元素格式的环境)
BFC (块级格式化上下文),是一个独立的渲染区域,让处于 BFC 内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用
目的:清除浮动 / 防止父子元素 margin 折叠 / 两栏布局
BFC 规则
○ BFC 就是一个块级元素,块级元素会在垂直方向一个接一个的排列
○ BFC 就是页面中的一个隔离的独立容器,容器里的标签不会影响到外部标签
○ 垂直方向的距离由 margin 决定, 属于同一个 BFC 的两个相邻的标签外边距会发生重叠
○ 计算 BFC 的高度时,浮动元素也参与计算
触发 BFC 的条件
○ float 不为 none
○ position 为 absolute fixed
○ overflow 不是 visible
○ display 为 flex inline-block table-cell 等
常用的情景 清除浮动 margin 重叠 -
flex:1
一个简写属性,用来设置 flex-grow, flex-shrink 与 flex-basis
flex-grow 属性定义弹性盒子项(flex item)的拉伸因子。
flex-shrink 属性指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。
flex-basis 指定了 flex 元素在主轴方向上的初始大小。如果不使用 box-sizing 改变盒模型的话,那么这个属性就决定了 flex 元素的内容盒(content-box)的尺寸。
● flex: 1; === flex: 1 1 0; -
居中对齐的实现方式
水平居中和垂直居中,方法很多,我这里就不列举了。 -
js 判断数据类型的方法
判断 js 中的数据类型有以下几种方法:
typeof(其中数组、对象、null 都会被判断为 Object,其他判断都正确)、
instanceof(只能判断引用数据类型,不能判断基本数据类型)、
constructor(它有 2 个作用 一是判断数据的类型,二是对象实例通过 constructor 对象访问它的构造函数。需要注意的事情是如果创建一个对象来改变它的原型,constructor 就不能来判断数据类型了)、
prototype、
通常情况下用 typeof 判断就可以了,遇到预知 Object 类型的情况可以选用 instanceof 或 constructor 方法 -
Js 防抖和节流:
○ Js 防抖的基本思路(技能前摇 - 电梯):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。防抖重在清零
○ 场景:
■ 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
■ 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
■ 文本编辑器实时保存,当无任何更改操作一秒后进行保存
○ JS 中节流的基本思路是(技能 CD):规定一个期限时间,在该时间内,触发事件的回调函数只能执行一次,如果期限时间内回调函数被多次触发,则只有一次能生效。节流重在加锁
○ 场景:
■ scroll 事件,每隔一秒计算一次位置信息等
■ 浏览器播放事件,每个一秒计算一次进度信息等
■ input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可做防抖) -
同步和异步的区别、宏任务 与 微任务
这个一般会伴随着考题一起出,举个栗子🌰
![]()
答:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
-
对 ES6 的理解
○ 新增模板字符串(为 JavaScript 提供了简单的字符串插值功能)可以使用反引号 `` 来进行字符拼接。${}
○ 箭头函数
○ for-of(用来遍历数据 — 例如数组中的值。)
○ arguments 对象可被不定参数和默认参数完美代替。
○ ES6 将 promise 对象纳入规范,提供了原生的 Promise 对象,更优雅地处理异步请求。
○ async/await 比 promise 更好的解决了回调地狱。
○ 增加了 let 和 const 命令,用来声明变量。
○ 增加了块级作用域。
○ 导入 improt,导出 export default
○ let 命令实际上就增加了块级作用域。
○ 还有就是引入 module 模块的概念
○ 加了 Map 和 Set 两种新的数据结构 -
React 生命周期、组件间通信
-
setState 是同步的还是异步的?
先给出答案:有时表现出异步,有时表现出同步
假如所有 setState 是同步的,意味着每执行一次 setState 时(有可能一个同步代码中,多次 setState),都重新 vnode diff + dom 修改,这对性能来说是极为不好的。如果是异步,则可以把一个同步代码中的多个 setState 合并成一次组件更新。所以默认是异步的,但是在一些情况下是同步的。
setState 并不是单纯同步 / 异步的,它的表现会因调用场景的不同而不同。在源码中,通过 isBatchingUpdates 来判断 setState 是先存进 state 队列还是直接更新,如果值为 true 则执行异步操作,为 false 则直接更新。
● 异步: 在 React 可以控制的地方,就为 true,比如在 React 生命周期事件和合成事件中,都会走合并操作,延迟更新的策略。
● 同步: 在 React 无法控制的地方,比如原生事件,具体就是在 addEventListener 、setTimeout、setInterval 等事件中,就只能同步更新。
一般认为,做异步设计是为了性能优化、减少渲染次数:
● setState 设计为异步,可以显著的提升性能。如果每次调用 setState 都进行一次更新,那么意味着 render 函数会被频繁调用,界面重新渲染,这样效率是很低的;最好的办法应该是获取到多个更新,之后进行批量更新;
● 如果同步更新了 state,但是还没有执行 render 函数,那么 state 和 props 不能保持同步。state 和 props 不能保持一致性,会在开发中产生很多的问题; -
为什么有时连续多次 setState 只有一次生效?
调用 setState 时,组件的 state 并不会立即改变, setState 只是把要修改的 state 放入一个队列, React 会优化真正的执行时机,并出于性能原因,会将 React 事件处理程序中的多次 React 事件处理程序中的多次 setState 的状态修改合并成一次状态修改。 最终更新只产生一次组件及其子组件的重新渲染,这对于大型应用程序中的性能提升至关重要。
需要注意的是,只要同步代码还在执行,“攒起来” 这个动作就不会停止。(注:这里之所以多次 +1 最终只有一次生效,是因为在同一个方法中多次 setState 的合并动作不是单纯地将更新累加。比如这里对于相同属性的设置,React 只会为其保留最后一次的更新)。 -
虚拟 Dom 是什么
-
传统 diff 和 React 的 diff 的区别
传统 diff:传统 Diff 算法需要找到两个树的最小更新方式,所以需要 [两两] 对比每个叶子节点是否相同,对比就需要 O (n2) 了,再加上更新(移动、创建、删除)时需要遍历一次,所以是 O (n3)
Reactdiff: 计算出 Virtual DOM 中真正变化的部分,并只针对该部分进行原生 DOM 操作,而非重新渲染整个页面使用三大策略 将 O (n^3) 复杂度 转化为 O (n) 复杂度 -
什么是 fiber,fiber 解决了什么问题
React15 的 StackReconciler 方案由于递归不可中断问题,如果 Diff 时间过长(JS 计算时间),会造成页面 UI 的无响应(比如输入框)的表现,vdom 无法应用到 dom 中。
为了解决这个问题,React16 实现了新的基于 requestIdleCallback 的调度器(因为 requestIdleCallback 兼容性和稳定性问题,自己实现了 polyfill),通过任务优先级的思想,在高优先级任务进入的时候,中断 reconciler。
为了适配这种新的调度器,推出了 FiberReconciler,将原来的树形结构(vdom)转换成 Fiber 链表的形式(child/sibling/return),整个 Fiber 的遍历是基于循环而非递归,可以随时中断。
更加核心的是,基于 Fiber 的链表结构,对于后续(React 17 lane 架构)的异步渲染和 (可能存在的)worker 计算都有非常好的应用基础 -
HTTP 状态码
-
301 和 302 的区别
-
http 中常见的 header 字段有哪些?
cookie,请求时传递给服务端的 cookie 信息 set-cookie,响应报文首部设置要传递给客户端的 cookie 信息 allow,支持什么 HTTP 方法 last-modified,资源的最后修改时间 expires, 设置资源缓存的失败日期 content-language,实体的资源语言 content-encoding,实体的编码格式 content-length,实体主体部分的大小单位是字节 content-range,返回的实体的哪些范围 content-type,哪些类型 accept-ranges,处理的范围请求 age,告诉客户端服务器在多久前创建了响应 vary,代理服务器的缓存信息 location,用于指定重定向后的 URI If-Match,值是资源的唯一标识 User-Agent,将创建请求的浏览器和用户代理名称等信息传递给服务器 Transfer-Encoding,传输报文的主体编码方式 connection,管理持久连接,keep-alive , close Cache-Control,控制浏览器的强缓存 -
cookies,session,sessionStroage 和 localStorage 的区别
-
缓存机制
Web 缓存大致可以分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN 缓存)、浏览器缓存。
浏览器缓存也包含很多内容: HTTP 缓存、indexDB、cookie、localstorage 等等。这里我们只讨论 HTTP 缓存相关内容。
● 缓存命中率:从缓存中得到数据的请求数与所有请求数的比率。理想状态是越高越好。
● 过期内容:超过设置的有效时间,被标记为 “陈旧” 的内容。通常过期内容不能用于回复客户端的请求,必须重新向源服务器请求新的内容或者验证缓存的内容是否仍然准备。
● 验证:验证缓存中的过期内容是否仍然有效,验证通过的话刷新过期时间。
失效:失效就是把内容从缓存中移除。当内容发生改变时就必须移除失效的内容。 -
浏览器缓存(强缓存 / 协商)
协商缓存 (etag,last-mofify) 和强制缓存(cache-control)。
浏览器加载一个页面的简单流程如下:- 浏览器先根据这个资源的 http 头信息来判断是否命中强缓存。如果命中则直接加在缓存中的资源,并不会将请求发送到服务器。
- 如果未命中强缓存,则浏览器会将资源加载请求发送到服务器。服务器来判断浏览器本地缓存是否失效。若可以使用,则服务器并不会返回资源信息,浏览器继续从缓存加载资源。
- 如果未命中协商缓存,则服务器会将完整的资源返回给浏览器,浏览器加载新资源,并更新缓存。
复杂流程:
浏览器第一次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header,以供下次加载时对比使用;
下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持 HTTP1.1,则使用 expires 头判断是否过期;
如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的请求;
服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;
如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200
-
从浏览器输入 url,发生了什么
-
三次握手和四次挥手
-
https 为什么是安全的?非对称加密解密的过程?
-
跨域问题是如何产生的?如何解决跨域问题
-
关于 HTTP2.0 的认识(https)
-
性能优化
打包优化、图片优化、加载优化等等,这个很重要,每个点都可以深度的聊 -
什么是微前端
-
TypeScript 常用的类型
-
状态管理方案
useReducer、recoil、redux、context 等详细聊聊
# 总结
从金三银四开始找工作,虽然感觉面试表现并不差,但是也有各方面原因没了下文,感觉行情还是不太好。还好我是在职找,心态很平稳,面了两个月,最终在阴差阳错之下收到了三年前梦中情司的 offer,流程很快,不愧是我的梦中情司,各方面对我来说都很满意了,也就不打算再继续面了,收到 offer 当天就和前司 ld 说我不干了!交接吧!

工作了快三年,终于能 gap 一段时间了,把一直想去的地方都去了一遍,回来美美入职~
最后最重要的一点,祝愿看我这篇文章的大家都能顺利找到满意的工作~

