《前端面试总结点线面》系列是为了收拢杂而乱的前端领域知识,由点及线,再涉及面,目的是为帮助广大前端同学复习巩固或查漏补缺或增删改查,为了更好的建立前端领域知识体系,为了更好的为前端面试做好准备,从而做一个合格、进步的前端开发工程师。
JavaScript
ES
- ES6
- let const class module
- arrow function, 函数参数默认值
- 模版字符串
- 赋值解构
- 剩余操作符
- promise generator
- ES7
- Array.prototype.includes
- 指数操作符 **
- ES8
- async/await
- Object.values/Object.entries
- String padding
- Object.getOwnPropertyDescriptors
- ES9
- Promise.finally
- 异步迭代 for await of
- ES10
- JSON.stringify
- Array.prototype.flat
- BigInt
EventLoop
EventLoop 是一个程序结构,用于等待和发送消息和事件。 程序中设置两个线程,一个负责程序本身的运行,叫做主线程;另一个负责主线程与其他线程(主要是 IO 操作)的通信,称为 EventLoop 线程(消息线程)。 主线程开始运行,每当遇到 IO 操作,主线程就让 EventLoop 线程通知相应的 IO 程序,主线程接着往后运行,当 IO 完成之后,EventLoop 线程再把结果返回主线程。主线程调用事先设定的回调函数,完成任务。
任务队列
- 所有同步任务都在主线程上运行,形成一个执行栈(execution context stack)
- 主线程之外还存在一个任务队列(task queue),只要异步任务有了结果,就在任务队列放置一个事件
- 一旦执行栈中所有的同步任务执行完毕,系统就会读取任务队列,进入执行栈。
- 主线程不断重复第三步。
Event Loop
主线程在运行的时候,会产生堆(heap)和栈(stack),栈中的代码调用各种外部 API,它们在任务队列中加入各种事件(click,load,done)。只要栈中的代码执行(同步任务)完毕,主线程就会去读取任务队列(异步任务),依次执行那些事件对应的回调函数。
宏任务 macrotask
setTimeout, setInterval, setImmediate, I/O, callabck, UI 渲染, MessageChannel
优先级: 主代码块 > setImmediate > postMessage > setTimeout/Interval
微任务 microtask
process.nextTick,Promise, MutationObserver, Async
优先级: process.nextTick > Promise > MutationObserver
微任务意义:
减少更新时的渲染次数因为根据 HTML 标准,会在宏任务执行结束之后,在下一个宏任务开始执行之前,UI 都会重新渲染。如果在 microtask 中就完成数据更新,当 macro-task 结束就可以得到最新的 UI 了。如果新建一个 macro-task 来做数据更新的话,那么渲染会执行两次
执行顺序
- 执行 macrotask 队列的一个任务
- 执行当前 microtask 队列的所有任务
- UI render
- 浏览器只保证 requestAnimationFrame 在重绘之前执行,没有确定的时间,何时重绘由浏览器决定。
- requestIdleCallback 在重绘之后执行,并且是否有空执行要看浏览器的调度,如果一定要在某个时间内执行,调用 timeout 参数。
示例 1:
示例 2:
垃圾回收 GC
- 标记清除法
- 将不再使用的对象标记为“无法到达的对象”,即从根部(全局对象)开始定时扫描内存中的对象,凡事能从根部到达的对象,保留。那些从根部出发无法触及的对象被标记为不可使用,稍后进行回收。
- 垃圾收集器在运行的时候给存储在内存中的所有变量添加标记,然后他会去掉环境中的变量和被环境中的变量引用的变量的标记,而在此之后再被添加标记的变量被视为准备删除的变量,原因是环境中的变量已经无法访问这些变量了。最后垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
- 引用计数法 垃圾收集器跟踪收集每个值被引用的次数。当声明一个变量并将一个引用类型的值赋给该变量时,则这个值的引用次数为 1,如果同一个值又被赋给另一个变量,则值的引用次数加 1。相反,如果包含这个值的变量又取得另一个值,则这个值的引用次数减 1。当这个值的引用次数为 0,就表示没有办法再访问这个值,就可以将其内存空间回收起来,当垃圾回收器下一次运行的时候,就会回收那些引用次数为 0 的值所占用的内存空间。
内存泄漏
- 意外的全局变量
- 使用
use strict
严格模式
- 使用
- 被遗忘的计时器或回调函数
clearTimeout
/clearInterval
/removeEventListener
- 脱离 DOM 元素的引用
WeakMap
/WeakSet
弱引用
- 闭包
调用堆栈
执行上下文
- 全局执行上下文 - 全局对象(this 指向这个对象)
- 函数执行上下文 - 函数被调用的时候创建
- EVAL 函数执行上下文 - eval 环境中
执行栈:用于存储在代码执行期间创建的所有上下文,LIFO(后进先出)
执行上下文创建
- 确定 this 的值,thisBinding
- 全局执行上下文,this 指向全局对象,浏览器->window,nodejs -> 文件 module 对象
- 函数执行上下文,this 的值取决于函数的调用方式(默认、隐式、显示、硬、new 绑定、箭头函数)
- 词法环境(Lexical Environment) 创建 - 存储 函数声明和 let、const 绑定
- 环境记录(EnvironmentRecord):存储函数和变量声明实际位置
- 全局环境 - 全局变量和全局对象
- 函数环境 - 包括 arguments 对象
- 对外部环境的引用(outer):可以访问其外部词法环境
- 全局 - null
- 函数 - 全局或引用环境
- 环境记录(EnvironmentRecord):存储函数和变量声明实际位置
- 变量环境(Variable Environment) 创建 - 仅存储 var 变量绑定
GlobalExectionContext = { ThisBinding: <Global Object>, LexicalEnvironment: { EnvironmentRecord: { Type: "Object", // 标识符绑定在这里 a: < uninitialized >, b: < uninitialized >, multiply: <