前端面试速记
1. this
- 箭头函数没有作用域,this 指向上一级
2. 闭包
为什么使用闭包?
- 避免变量被污染
- 私有化
- 保存变量,常驻内存
;(function fn () { |
使用场景
- 防抖和节流中也会用到闭包
- 库的封装(保证数据私有性)
例子
// 计数器 |
2.1 匿名自执行函数
特点
- 自执行 => 单例模式
- 防止变量污染
;(function (window) {})(window) |
应用
jQuery
以下代码尝试封装 jQuery
(function (window){ |
优化上述代码
let $ = (jquery = (function (window) { |
代码解释:这段代码采用了一个立即执行函数表达式(IIFE),它返回一个函数,这个函数又返回一个新的对象。这里的第一个 return 语句是为了返回这个函数,以便在代码中使用 $ 或 jquery 来创建一个新的对象。第二个 return 语句是为了确保每次调用 $ 或 jquery 时都会返回一个新的对象,而不是返回同一个对象的引用。这样可以避免多个地方同时对同一个对象进行操作时产生的副作用。
再次优化
let $ = (jQuery = (function (window) { |
3. 空对象
let obj = Object.create(null)与let obj2 = {}的区别
obj没有原型链,obj2有__proto__- 使用
obj来存数据,运行效率比obj2更快,因为obj没有原型链,找不到数据不用向上变量原型链
4. 事件委托
解释:如果要作用到当前节点,可以作用到上一层节点中,用上层节点进行委托。比如<li>标签有点击事件,可以使用<ul>标签(当前<li>标签的上层)接收点击事件,作用时,判断是不是<li>标签即可。
例子
let ul = document.getElementById('ul') |
5. 原型链
6. 对象
可以在对象中使用方括号获取变量的值作为键
let user1 = 'John' |
7. ??与||的区别
const x = undefined ?? 'default' // x = 'default' |
|| 只会在左边的值为假值时返回右边的值 (0, ‘’, undefined, null, false 等都为假值)
?? 是在左边的值为 undefined 或者 null 时才会返回右边的值
8. 前端性能优化
8.1 路由懒加载
// 通过webpackChunkName设置分割后代码块的名字 |
懒加载前提的实现:ES6 的动态地加载模块——import()
8.2 组件懒加载
只有使用到该组件时,才会加载对应的文件
<script> |
使用场景
- 该页面的 JS 文件体积大,导致页面打开慢,可以通过组件懒加载进行资源拆分,利用浏览器并行下载资源,提升下载速度(比如首页)
- 该组件不是一进入页面就展示,需要一定条件下才触发(比如弹框组件)
- 该组件复用性高,很多页面都有引入,利用组件懒加载抽离出该组件,一方面可以很好利用缓存,同时也可以减少页面的 JS 文件大小(比如表格组件、图形组件等)
8.3 合理使用 Tree shaking
Tree shaking 的理解:是一种用于优化 JavaScript 代码的技术,消除无用的 JS 代码,减少代码体积。
如果代码存在副作用(如修改全局变量或调用接口等),那么这部分代码是不会被删除的。
// util.js |
项目中只使用了 targetType 方法,但未使用 deepClone 方法,项目打包后,deepClone 方法不会被打包到项目里
// util.js |
无法通过静态分析判断出一个对象的哪些变量未被使用,所以 tree-shaking 只对使用 export 导出的变量生效
8.4 骨架屏优化白屏时长
使用骨架屏优化白屏时间
骨架屏插件:vue-skeleton-webpack-plugin
8.5 长列表虚拟滚动
通过虚拟滚动列表,即数据滚动,dom 元素固定个数不再新增
虚拟滚动的插件:vue-virtual-scroller、vue-virtual-scroll-list、react-tiny-virtual-list、react-virtualized
8.6 Web Worker 优化长任务
GUI 渲染线程与 JS 引擎线程是互斥的关系,当页面中有很多长任务时,会造成页面 UI 阻塞,出现界面卡顿、掉帧等情况
(通信时长:新建一个 web worker 时, 浏览器会加载对应的 worker.js 资源)
当任务的运算时长 - 通信时长 > 50ms,推荐使用 Web Worker
8.7 requestAnimationFrame 制作动画
requestAnimationFrame 是浏览器专门为动画提供的 API,它的刷新频率与显示器的频率保持一致,使用该 api 可以解决用 setTimeout/setInterval 制作动画卡顿的情况
setTimeout/setInterval、requestAnimationFrame 三者的区别:
1)引擎层面
setTimeout/setInterval 属于 JS引擎,requestAnimationFrame 属于 GUI引擎
JS引擎与GUI引擎是互斥的,也就是说 GUI 引擎在渲染时会阻塞 JS 引擎的计算
2)时间是否准确
requestAnimationFrame 刷新频率是固定且准确的,但 setTimeout/setInterval 是宏任务,根据事件轮询机制,其他任务会阻塞或延迟 js 任务的执行,会出现定时器不准的情况
3)性能层面
当页面被隐藏或最小化时,setTimeout/setInterval 定时器仍会在后台执行动画任务,而使用 requestAnimationFrame 当页面处于未激活的状态下,屏幕刷新任务会被系统暂停
8.8 JS 的 6 种加载方式
8.8.1 正常模式
<script src='index.js'></script> |
这种情况下 JS 会阻塞 dom 渲染,浏览器必须等待 index.js 加载和执行完成后才能去做其它事情
8.8.2 async 模式
<script async src='index.js'></script> |
async 模式下,它的加载是异步的,JS 不会阻塞 DOM 的渲染,async 加载是无顺序的,当它加载结束,JS 会立即执行
使用场景:若该 JS 资源与 DOM 元素没有依赖关系,也不会产生其他资源所需要的数据时,可以使用 async 模式,比如埋点统计
(埋点统计:通过一定的方式记录用户行为和操作,将这些数据发送到服务器进行处理和分析,从而了解用户的行为习惯、流量来源、使用习惯等信息。页面 PV(Page View)统计、点击事件统计、表单提交统计、Ajax 请求统计、错误信息统计)
8.8.3 defer 模式
<script defer src='index.js'></script> |
defer 模式下,JS 的加载也是异步的,defer 资源会在 DOMContentLoaded 执行之前,并且 defer 是有顺序的加载
如果有多个设置了 defer 的 script 标签存在,则会按照引入的前后顺序执行,即便是后面的 script 资源先返回
应用场景
控制资源加载顺序
<script defer src="vue.js"></script> |
8.8.4 module 模式
<script type='module'>import {a} from './a.js'</script> |
浏览器会对其内部的import引用发起 HTTP 请求,获取模块内容。这时 script 的行为会像是 defer 一样,在后台下载,并且等待 DOM 解析
8.8.5 preload
link 标签的 preload 属性:用于提前加载一些需要的依赖,这些资源会优先加载
<link rel="preload" as="script" href="index.js"> |
特点
- preload 加载的资源是在浏览器渲染机制之前进行处理的,并且不会阻塞 onload 事件;
- preload 加载的 JS 脚本其加载和执行的过程是分离的,即 preload 会预加载相应的脚本代码,待到需要时自行调用;
8.8.6 prefetch
<link rel="prefetch" as="script" href="index.js"> |
prefetch 是利用浏览器的空闲时间,加载页面将来可能用到的资源的一种机制;通常可以用于加载其他页面(非首页)所需要的资源,以便加快后续页面的打开速度
8.9 图片的优化
8.9.1 图片的动态裁剪
只需在图片的 url 上动态添加参数,就可以得到需要的尺寸大小
8.9.2 图片的懒加载
<script> |
插件推荐:vue-lazyload
8.9.3 使用字体图标
字体图标的优点:
- 轻量级:一个图标字体要比一系列的图像要小。一旦字体加载了,图标就会马上渲染出来,减少了 http 请求
- 灵活性:可以随意的改变颜色、产生阴影、透明效果、旋转等
- 兼容性:几乎支持所有的浏览器,请放心使用
8.9.4 图片转 base64 格式
将小图片转换为 base64 编码字符串,并写入 HTML 或者 CSS 中,减少 http 请求
优缺点:
1)它处理的往往是非常小的图片,因为 Base64 编码后,图片大小会膨胀为原文件的 4/3,如果对大图也使用 Base64 编码,后者的体积会明显增加,即便减少了 http 请求,也无法弥补这庞大的体积带来的性能开销,得不偿失;(空间换时间)
2)在传输非常小的图片的时候,Base64 带来的文件体积膨胀、以及浏览器解析 Base64 的时间开销,与它节省掉的 http 请求开销相比,可以忽略不计,这时候才能真正体现出它在性能方面的优势
9. 函数表达式、函数声明
- 变量提升
- 函数声明提升
var foo = function () { |
表达式提升:无论在哪个位置使用var声明一个变量,该变量都会在整段程序最上端,因此在使用var声明他之前调用他,会显示undefined
foo() |
函数声明提升:函数声明会在任何代码执行之前先被读取并添加到执行上下文,如果出现重复的函数声明,最后的声明会替换前面的声明,因此无论哪个位置执行该函数都会执行最后声明的函数内容
function foo() { |
10. valueOf与toString的区别
valueOf()方法返回对象的原始值。例如,当使用一个对象进行数学运算时,JavaScript会自动调用valueOf()方法来获取对象的原始值进行计算。
toString()方法返回对象的字符串表示。它将对象转换为字符串,并返回该字符串。
var num = 10; |







