浅窥前端技能知识深度

95 阅读5分钟

浅窥前端技能知识深度

本章总结前端技术深度相关面试题。包括 JS 内存相关,Vue 相关原理。 大厂的技术评级时,技术深度是重要的参考标准。

JS内存泄漏如何检测?场景有哪些?

垃圾回收机制
什么是垃圾回收机制?

有些数据不再被引用时,JS的垃圾回收机制会清除该数据。

引用树机制(之前的算法)

每当数据被引用时,引用树就会添加一条引用信息,接下来只需要判断引用树的长度即可。

但引用树机制有个问题,当出现循环引用,如

function fn(){
  const obj1 = {}
  const obj2 = {}
  obj1.a = obj2
  obj2.a = obj1
}

函数执行完引用树也不会归零,产生内存泄漏。

标记清除(现在的算法)

定期从window遍历所有属性,如果能得到保留,不能得到删除。

闭包是内存泄漏么?

内存泄漏是指产生了意料之外的不回收的垃圾。

闭包严格意义上不是内存泄漏,是人为指定的意料之中的。

如何检测内存泄漏?

chrome调试工具中的profromance中可以录制内存快照,包括内存,CPU,FPS等信息,观察曲线变化就可以检查是否有大量的内存泄漏。

内存泄漏的场景(以VUE为例)
  • 被全局变量,函数引用,组件销毁时未清除
  • 被全局事件,定时器引用,组件销毁时未清除
  • 被自定义事件引用,组件销毁时未清除
在beforeUnmount删除所有window的监听器,删除所有的定时器,计时器,自定义事件。
WeakMap WeakSet弱引用

先看个使用普通对象的例子

const data = {}
function fn1 () {
  const obj = { x: 100 }
  data.obj = obj
}
fn1()

在data中可以查找到obj的引用,根据标记清除法,不会回收obj

如果使用weakMap,里面存储的内容有引用也可能被回收。

const wMap = new WeakMap()
function fn1 () {
  const obj = { x: 100 }
  wMap.set(obj, 100) //WeakMap的key只能是引用类型
}
fn1()
  • WeakMap的key只能是引用类型
  • weakMap不能被循环,没有size(它自己也不确定自己的内容是否被回收了
  • 当某个场景,你想要回收某个变量,但又不想被其他引用干扰,可以使用weakMap建立引用关系。

浏览器和nodejs的事件循环有什么区别?

单线程和异步
  • JS是单线程的(无论是浏览器还是node)
  • 浏览器JS和DOM渲染公用一个线程
宏任务和微任务
  • 宏任务:如setTImeout setInterval 网络请求
  • 微任务:如promise async/await
  • 微任务在下一轮DOM渲染前执行,宏任务在之后进行
Nodejs的异步
  • nodejs同样使用ES语法,也是单线程,也需要异步
  • 异步也分为:宏任务+微任务
  • 但是,它的宏任务和微任务,分不同类型,有不同优先级。
Nodejs宏任务的优先级
  • Timer -setTImeout,setInterveal
  • I/O callback - 处理网络 流 TCP的错误回调
  • Idle,prepare - 闲置状态
  • Poll轮询,执行poll中的I/O队列
  • Ckeck检查,存储SetImmediate回调
  • CloseCallbacks 关闭回调
Nodejs微任务优先级
  • process.nextTick优先级最高
  • 其他都相同

VODM真的很快么?

  • Virtual DOM 虚拟DOM
  • 用JS对象模拟DOM节点的数据
为什么要使用前端框架?
  • 组件化
  • 数据视图分离,数据驱动视图
  • 只关注业务数据,而不在关心DOM变化
VODM真的比JS操作DOM快么?
  • VDOM : 1. data变化 2.vnode diff 3.更新DOM
  • JS:直接操纵

VOMD快只是相较于全局更新DOM,它节省了一些无需更新的视图。比JS直接操纵慢。

但他实现了数据视图分离。

for和foreach谁更快 为什么?

  • for更快
  • forEach每次都要创建一个函数来调用,而for不会
  • 函数需要独立的作用域,会有额外开销

Vue的生命周期每一步都做了什么?

beforeCreate
  • 创建一个空白的Vue实例
  • data method尚未被初始化,不可使用
created
  • vue实例初始化完成,完成响应式绑定
  • data method都已经初始化完成,可调用
  • 尚未开始渲染模版
beforeMount
  • 编译模版,调用render生成vdom
  • 还没有开始DOM渲染
mounted
  • 完成DOM渲染
  • 组件创建完成
  • 开始由“创建阶段”进行运行阶段
beforeUpdate
  • 数据更新
  • DOM还未更新
updated
  • data变化,DOM更新完成
  • 不要再uptaded修改data,会造成死循环
beforeUnmount
  • 组件进入销毁阶段
  • 可以移除,解绑一些全局事件,自定义事件
unmounted
  • 组件被销毁了
  • 所有子组件也被销毁了

在使用keepalive也有两个钩子函数,在被激活和被隐藏触发。(avticed,deacticed)

Vue什么时候操作DOM比较合适?
  • mounted和updated都不能保证子组件全部挂载完成
  • 使用$nextTick渲染DOM

Vue2 Vue3 React的diff算法有什么不同?

介绍diff算法
  • diff算法很早就有
  • diff算法应用广泛,如github上的pull request中的代码diff
  • 如果要严格diff两棵树,时间复杂度O(n*3) 不可用
Tree diff的优化
  • 只比较同一层级,不跨级比较
  • tag 不同则删掉重建(不再去比较内部的细节)
  • 子节点通过 key 区分( key 的重要性)
  • 时间复杂度O(n)
React diff - 仅右移
  • 如果比较后发现新节点在左面,不移动,新节点在右面就右移
Vue2 双端比较

维护四个指针,双端向中心移动。

Vue3 最长递增子序列

记录下不同部分的节点的序列,选取最长递增子序列,子序列不做操作,操作其他序列。

Vue路由的第三种模式?

Vue-router实际上支持三种模式

  • hash
  • WebHsitory
  • MemoryHsitory(abstract history)

区别于其他两种模式,MemoryHsitory不支持前进后退,也不会改变地址栏,也不会刷新,只会改变页面的内容。