最新的前端大厂面经(详解答案)

2021-09-16 原文地址:https://juejin.cn/post/7004638318843412493?utm_source=gold_browser_extension#heading-39

最新的前端大厂面经(详解答案) 简单1 从输入一个 URL 地址到浏览器完成渲染的整个过程2 什么是事件代理(事件委托) 有什么好处3 addEventListener 默认是捕获还是冒泡4 css 的渲染层合成是什么 浏览器如何创建新的渲染层5 webpack Plugin 和 Loader 的区别6.apply call bind 区别7 举出闭包实际场景运用的例子8 css 优先级是怎么计算的9 事件循环相关题目--必考(一般是代码输出顺序判断)10 http 状态码 204 301 302 304 400 401 403 404 含义11 http2.0 做了哪些改进 3.0 呢12 position 有哪些值,作用分别是什么13 垂直水平居中实现方式14 vue 组件通讯方式有哪些方法15 Vue 响应式原理16 Vue nextTick 原理17 Vue diff 原理18 路由原理 history 和 hash 两种路由方式的特点19 手写 bind19 手写 promise.all 和 race(京东)20 手写-实现一个寄生组合继承21 手写-new 操作符22 手写-setTimeout 模拟实现 setInterval(阿里)23 手写-发布订阅模式(字节)24 手写-防抖节流(京东)25 手写-将虚拟 Dom 转化为真实 Dom(类似的递归题-必考)26 手写-实现一个对象的 flatten 方法(阿里)27 手写-判断括号字符串是否有效(小米)28 手写-查找数组公共前缀(美团)29 手写-字符串最长的不重复子串30 手写-如何找到数组中第一个没出现的最小正整数 怎么优化(字节)31 手写-怎么在制定数据源里面生成一个长度为 n 的不重复随机数组 能有几种方法 时间复杂度多少(字节)中等1 Webpack 有哪些优化手段2 css 怎么开启硬件加速(GPU 加速)3 常用设计模式有哪些并举例使用场景4 浏览器缓存策略是怎样的(强缓存 协商缓存)具体是什么过程?5 https 加密过程是怎样的6 flex:1 是哪些属性组成的7 304 是什么意思 一般什么场景出现 ,命中强缓存返回什么状态码8 手写 Vue.extend 实现9 vue-router 中路由方法 pushState 和 replaceState 能否触发 popSate 事件10 tree shaking 是什么,原理是什么11 babel 是什么,原理了解吗12 原型链判断13 RAF 和 RIC 是什么困难1 Es6 的 let 实现原理2 如何设计实现一个渲染引擎3 require 具体实现原理是什么4 前端性能定位以及优化指标小结其他面试题系列链接

 

简单

1 从输入一个 URL 地址到浏览器完成渲染的整个过程

这个问题属于老生常谈的经典问题了 下面给出面试简单版作答

  1. 浏览器地址栏输入 URL 并回车
  2. 浏览器查找当前 URL 是否存在缓存,并比较缓存是否过期
  3. DNS 解析 URL 对应的 IP
  4. 根据 IP 建立 TCP 连接(三次握手)
  5. 发送 http 请求
  6. 服务器处理请求,浏览器接受 HTTP 响应
  7. 浏览器解析并渲染页面
  8. 关闭 TCP 连接(四次握手)

注意! 面试官可以基于这道题进行前端很多知识点的考察 从 http 网络知识到浏览器原理再到前端性能优化 这个题目都可以作为引子开始

所以推荐大家可以看看这篇详细作答 史上最详细的经典面试题 从输入 URL 到看到页面发生了什么?

2 什么是事件代理(事件委托) 有什么好处

事件委托的原理:不给每个子节点单独设置事件监听器,而是设置在其父节点上,然后利用冒泡原理设置每个子节点。

优点:

3 addEventListener 默认是捕获还是冒泡

默认是冒泡

addEventListener第三个参数默认为 false 代表执行事件冒泡行为。

当为 true 时执行事件捕获行为。

4 css 的渲染层合成是什么 浏览器如何创建新的渲染层

在 DOM 树中每个节点都会对应一个渲染对象(RenderObject),当它们的渲染对象处于相同的坐标空间(z 轴空间)时,就会形成一个 RenderLayers,也就是渲染层。渲染层将保证页面元素以正确的顺序堆叠,这时候就会出现层合成(composite),从而正确处理透明元素和重叠元素的显示。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常。

浏览器如何创建新的渲染层

注意!不少人会将这些合成层的条件和渲染层产生的条件混淆,这两种条件发生在两个不同的层处理环节,是完全不一样的 具体可以看看这篇文章 浏览器层合成与页面渲染优化

5 webpack Plugin 和 Loader 的区别

webpack 相关知识可以看鲨鱼哥这篇文章 前端进阶高薪必看-Webpack 篇 说的很通俗易懂 基本应对简单的面试足够了

6.apply call bind 区别

注意!很多同学可能会忽略 bind 绑定的函数作为构造函数进行 new 实例化的情况

7 举出闭包实际场景运用的例子

比如常见的防抖节流

使用闭包可以在 JavaScript 中模拟块级作用域

闭包可以用于在对象中创建私有变量

8 css 优先级是怎么计算的

9 事件循环相关题目--必考(一般是代码输出顺序判断)

输出结果:247536 async2 的结果 1

注意!我在最后一个 Promise 埋了个坑 我没有调用 resolve 方法 这个是在面试美团的时候遇到了 当时自己没看清楚 以为都是一样的套路 最后面试官说不对 找了半天才发现是这个坑 哈哈

10 http 状态码 204 301 302 304 400 401 403 404 含义

11 http2.0 做了哪些改进 3.0 呢

http2.0 特性如下

Http3.0 相对于 Http2.0 是一种脱胎换骨的改变!

http 协议是应用层协议,都是建立在传输层之上的。我们也都知道传输层上面不只有 TCP 协议,还有另外一个强大的协议 UDP 协议,2.0 和 1.0 都是基于 TCP 的,因此都会有 TCP 带来的硬伤以及局限性。而 Http3.0 则是建立在 UDP 的基础上。所以其与 Http2.0 之间有质的不同。

http3.0 特性如下

建议大家详细看看这篇文章Http2.0 的一些思考以及 Http3.0 的优势

12 position 有哪些值,作用分别是什么

13 垂直水平居中实现方式

这道题基本也是 css 经典题目 但是网上已经有太多千篇一律的答案了 如果大家想在这道题加分

可以针对定宽高和不定宽高的实现多种不同的方案

建议大家直接看 面试官:你能实现多少种水平垂直居中的布局(定宽高和不定宽高)

14 vue 组件通讯方式有哪些方法

15 Vue 响应式原理

整体思路是数据劫持+观察者模式

对象内部通过 defineReactive 方法,使用 Object.defineProperty 将属性进行劫持(只会劫持已经存在的属性),数组则是通过重写数组方法来实现。当页面使用对应属性时,每个属性都拥有自己的 dep 属性,存放他所依赖的 watcher(依赖收集),当属性变化后会通知自己对应的 watcher 去更新(派发更新)。

相关代码如下

响应式数据原理详解 传送门

16 Vue nextTick 原理

nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法

相关代码如下

nextTick 原理详解 传送门

17 Vue diff 原理

diff算法.png

建议直接看 diff 算法详解 传送门

18 路由原理 history 和 hash 两种路由方式的特点

hash 模式

  1. location.hash 的值实际就是 URL 中#后面的东西 它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
  2. 可以为 hash 的改变添加监听事件

每一次改变 hash(window.location.hash),都会在浏览器的访问历史中增加一个记录利用 hash 的以上特点,就可以来实现前端路由“更新视图但不重新请求页面”的功能了

特点:兼容性好但是不美观

history 模式

利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。

这两个方法应用于浏览器的历史记录站,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。这两个方法有个共同的特点:当调用他们修改浏览器历史记录栈后,虽然当前 URL 改变了,但浏览器不会刷新页面,这就为单页应用前端路由“更新视图但不重新请求页面”提供了基础。

特点:虽然美观,但是刷新会出现 404 需要后端进行配置

19 手写 bind

19 手写 promise.all 和 race(京东)

20 手写-实现一个寄生组合继承

21 手写-new 操作符

22 手写-setTimeout 模拟实现 setInterval(阿里)

23 手写-发布订阅模式(字节)

24 手写-防抖节流(京东)

25 手写-将虚拟 Dom 转化为真实 Dom(类似的递归题-必考)

答案

26 手写-实现一个对象的 flatten 方法(阿里)

题目描述

答案

27 手写-判断括号字符串是否有效(小米)

题目描述

答案

28 手写-查找数组公共前缀(美团)

题目描述

答案

29 手写-字符串最长的不重复子串

题目描述

答案

30 手写-如何找到数组中第一个没出现的最小正整数 怎么优化(字节)

这是一道字节的算法题 目的在于不断地去优化算法思路

31 手写-怎么在制定数据源里面生成一个长度为 n 的不重复随机数组 能有几种方法 时间复杂度多少(字节)

值得一提的是操作数组的时候使用交换法 这种思路在算法里面很常见

中等

1 Webpack 有哪些优化手段

随着项目越来越大,Webpack 构建速度可能会越来越慢,构建出来的 js 的体积也越来越大,此时就需要对 Webpack 的配置进行优化

这个知识点可以单独开一篇文章 大家请看 带你深度解锁 Webpack 系列(优化篇)

2 css 怎么开启硬件加速(GPU 加速)

浏览器在处理下面的 css 的时候,会使用 GPU 渲染

注意!层爆炸,由于某些原因可能导致产生大量不在预期内的合成层,虽然有浏览器的层压缩机制,但是也有很多无法进行压缩的情况,这就可能出现层爆炸的现象(简单理解就是,很多不需要提升为合成层的元素因为某些不当操作成为了合成层)。解决层爆炸的问题,最佳方案是打破 overlap 的条件,也就是说让其他元素不要和合成层元素重叠。简单直接的方式:使用 3D 硬件加速提升动画性能时,最好给元素增加一个 z-index 属性,人为干扰合成的排序,可以有效减少创建不必要的合成层,提升渲染性能,移动端优化效果尤为明显。

3 常用设计模式有哪些并举例使用场景

1.工厂模式 - 传入参数即可创建实例

虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode

2.单例模式 - 整个程序有且仅有一个实例

vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉

3.发布-订阅模式 (vue 事件机制)

4.观察者模式 (响应式数据原理)

5.装饰模式: (@装饰器的用法)

6.策略模式 策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案-比如选项的合并策略

...其他模式欢迎补充

4 浏览器缓存策略是怎样的(强缓存 协商缓存)具体是什么过程?

这个也是经典的前端缓存问题 知识点加起来是一篇文章了 推荐大家看 前端浏览器缓存知识梳理

5 https 加密过程是怎样的

使用了对称加密可非对称加密的混合方式

具体过程请看 前端进阶高薪必看-HTTPS 篇

6 flex:1 是哪些属性组成的

flex 实际上是 flex-grow、flex-shrink 和 flex-basis 三个属性的缩写。

flex-grow:定义项目的的放大比例;

flex-shrink:定义项目的缩小比例;

flex-basis: 定义在分配多余空间之前,项目占据的主轴空间(main size),浏览器根据此属性计算主轴是否有多余空间

7 304 是什么意思 一般什么场景出现 ,命中强缓存返回什么状态码

协商缓存命中返回 304

这种方式使用到了 headers 请求头里的两个字段,Last-Modified & If-Modified-Since 。服务器通过响应头 Last-Modified 告知浏览器,资源最后被修改的时间:

Last-Modified: Thu, 20 Jun 2019 15:58:05 GMT

当再次请求该资源时,浏览器需要再次向服务器确认,资源是否过期,其中的凭证就是请求头 If-Modified-Since 字段,值为上次请求中响应头 Last-Modified 字段的值:

If-Modified-Since: Thu, 20 Jun 2019 15:58:05 GMT

浏览器在发送请求的时候服务器会检查请求头 request header 里面的 If-modified-Since,如果最后修改时间相同则返回 304,否则给返回头(response header)添加 last-Modified 并且返回数据(response body)。

另外,浏览器在发送请求的时候服务器会检查请求头(request header)里面的 if-none-match 的值与当前文件的内容通过 hash 算法(例如 nodejs: cryto.createHash('sha1'))生成的内容摘要字符对比,相同则直接返回 304,否则给返回头(response header)添加 etag 属性为当前的内容摘要字符,并且返回内容。

综上总结为:

强缓存命中返回 200 200(from cache)

8 手写 Vue.extend 实现

具体可以看看这篇 手写 Vue2.0 源码(八)-组件原理

9 vue-router 中路由方法 pushState 和 replaceState 能否触发 popSate 事件

答案是:不能

pushState 和 replaceState

HTML5 新接口,可以改变网址(存在跨域限制)而不刷新页面,这个强大的特性后来用到了单页面应用如:vue-router,react-router-dom 中。

注意:仅改变网址,网页不会真的跳转,也不会获取到新的内容,本质上网页还停留在原页面

popstate 事件会在点击后退、前进按钮(或调用 history.back()、history.forward()、history.go()方法)时触发

注意:用 history.pushState()或者 history.replaceState()不会触发 popstate 事件

10 tree shaking 是什么,原理是什么

Tree shaking 是一种通过清除多余代码方式来优化项目打包体积的技术,专业术语叫 Dead code elimination

tree shaking 的原理是什么?

扩展:common.js 和 es6 中模块引入的区别?

CommonJS 是一种模块规范,最初被应用于 Nodejs,成为 Nodejs 的模块规范。运行在浏览器端的 JavaScript 由于也缺少类似的规范,在 ES6 出来之前,前端也实现了一套相同的模块规范 (例如: AMD),用来对前端模块进行管理。自 ES6 起,引入了一套新的 ES6 Module 规范,在语言标准的层面上实现了模块功能,而且实现得相当简单,有望成为浏览器和服务器通用的模块解决方案。但目前浏览器对 ES6 Module 兼容还不太好,我们平时在 Webpack 中使用的 export 和 import,会经过 Babel 转换为 CommonJS 规范。在使用上的差别主要有:

1、CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。

2、CommonJS 模块是运行时加载,ES6 模块是编译时输出接口(静态编译)。

3、CommonJs 是单个值导出,ES6 Module 可以导出多个

4、CommonJs 是动态语法可以写在判断里,ES6 Module 静态语法只能写在顶层

5、CommonJs 的 this 是当前模块,ES6 Module 的 this 是 undefined

11 babel 是什么,原理了解吗

Babel 是一个 JavaScript 编译器。他把最新版的 javascript 编译成当下可以执行的版本,简言之,利用 babel 就可以让我们在当前的项目中随意的使用这些新最新的 es6,甚至 es7 的语法。

Babel 的三个主要处理步骤分别是: 解析(parse),转换(transform),生成(generate)。

还想深入了解的可以看 [实践系列]Babel 原理

12 原型链判断

请写出下面的答案

这道题目深入考察了原型链相关知识点 尤其是 Function 和 Object 的之间的关系

强烈推荐大家看看这篇文章 看完就清楚了 JavaScript 原型系列(三)Function、Object、null 等等的关系和鸡蛋问题

13 RAF 和 RIC 是什么

requestAnimationFrame: 告诉浏览器在下次重绘之前执行传入的回调函数(通常是操纵 dom,更新动画的函数);由于是每帧执行一次,那结果就是每秒的执行次数与浏览器屏幕刷新次数一样,通常是每秒 60 次。

requestIdleCallback:: 会在浏览器空闲时间执行回调,也就是允许开发人员在主事件循环中执行低优先级任务,而不影响一些延迟关键事件。如果有多个回调,会按照先进先出原则执行,但是当传入了 timeout,为了避免超时,有可能会打乱这个顺序。

这个题目可以深入去问浏览器每一帧的渲染流程 具体可以看看这篇 requestIdleCallback 和 requestAnimationFrame 详解

困难

1 Es6 的 let 实现原理

原始 es6 代码

babel 编译之后的 es5 代码(polyfill)

其实我们根据 babel 编译之后的结果可以看得出来 let 是借助闭包和函数作用域来实现块级作用域的效果的 在不同的情况下 let 的编译结果是不一样的

2 如何设计实现一个渲染引擎

这道题是字节终面的最后一个题目 属于开放性问题 没有固定答案 我当时觉得题目概念太大了 把我整懵了 我只是回答了下浏览器渲染原理啥的 貌似面试官不太满意 哈哈 如果叫你设计一个渲染引擎 应该从哪些方面着手呢

大家可以参考看看文章 你不知道的浏览器页面渲染机制

3 require 具体实现原理是什么

require 基本原理

图片.png

require 查找路径

图片.png

require 和 module.exports 干的事情并不复杂,我们先假设有一个全局对象{},初始情况下是空的,当你 require 某个文件时,就将这个文件拿出来执行,如果这个文件里面存在 module.exports,当运行到这行代码时将 module.exports 的值加入这个对象,键为对应的文件名,最终这个对象就长这样:

当你再次 require 某个文件时,如果这个对象里面有对应的值,就直接返回给你,如果没有就重复前面的步骤,执行目标文件,然后将它的 module.exports 加入这个全局对象,并返回给调用者。这个全局对象其实就是我们经常听说的缓存。所以 require 和 module.exports 并没有什么黑魔法,就只是运行并获取目标文件的值,然后加入缓存,用的时候拿出来用就行。

具体可以看看这篇 深入 Node.js 的模块加载机制,手写 require 函数

4 前端性能定位以及优化指标

前端性能优化 已经是老生常谈的一项技术了 很多人说起性能优化方案的时候头头是道 但是真正的对于性能分析定位和性能指标这块却一知半解 所以这道题虽然和性能相关 但是考察点在于平常项目如何进行性能定位和分析

  1. 我们可以从 前端性能监控-埋点以及 window.performance相关的 api 去回答
  2. 也可以从性能分析工具 Performance 和 Lighthouse
  3. 还可以从性能指标 LCP FCP FID CLS 等去着手

以下为性能相关的文章 大家可以去看看

5 分钟撸一个前端性能监控工具

前端性能优化之谈谈通用性能指标及上报策略

前端性能优化指标 + 检测工具

小结

以上的面经仅仅是起到一个抛转引玉的作用 前端各种面试题层出不穷 咱们光是把答案记住是不行的 最终还是希望大家通过这篇面经深入学习前端知识点背后的原理 当然对于社招同学来说掌握了前端原理知识相关的题目是远远不够的 社招面试很重要的一点是过往项目经验以及项目亮点难点展示 这个靠刷题是刷不出来的 还是得靠大家在平常工作中不断的实践积累 拒绝当一名 cv 工程师

其他面试题系列链接