记一次在梦里的大厂面试情景
转自:_杨溜溜 segmentfault.com/a/1190000023949535
前言
来,先介绍一下Vue的响应式系统
computed与watch的区别
介绍一下Vue的生命周期
beforeCreate
:是new Vue()之后触发的第一个钩子,在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。
created
:在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom。
beforeMount
:发生在挂载之前,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。
mounted
:在挂载完成后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。
beforeUpdate
:发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。
updated
:发生在更新完成之后,当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。
beforeDestroy
:发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。
destroyed
:发生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。
为什么组件的data必须是一个函数
组件之间是怎么通信的
-
父子组件通信
prop
$on/$emit
$parent/$children
,$refs.xxx
,获取到实例后直接获取属性数据或调用组件方法
-
兄弟组件通信
$on/$emit
,可以为兄弟组件的实例之间new一个Vue实例,作为Event Bus进行通信。
-
跨级组件通信
Vue事件绑定原理说一下
$on
方法将事件注册到内部,在需要的时候使用$emit
触发函数,而对于原生native事件,使用addEventListener绑定到真实的DOM元素上。
slot是什么?有什么作用?原理是什么?
-
默认插槽:又名匿名查抄,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。 -
具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。 -
作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。
vm.$slot
中,默认插槽为vm.$slot.default
,具名插槽为vm.$slot.xxx
,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot
中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。
Vue模板渲染的原理是什么?
-
parse阶段:使用大量的正则表达式对template字符串进行解析,将标签、指令、属性等转化为抽象语法树AST。 -
optimize阶段:遍历AST,找到其中的一些静态节点并进行标记,方便在页面重渲染的时候进行diff比较时,直接跳过这一些静态节点,优化runtime的性能。 -
generate阶段:将最终的AST转化为render函数字符串。
template预编译是什么?
render function
,这个过程,正好可以在项目构建的过程中完成,这样可以让实际组件在 runtime 时直接跳过模板渲染,进而提升性能,这个在项目构建的编译template的过程,就是预编译。
那template和jsx的有什么分别?
vue-loader
编译.vue文件,内部依赖的vue-template-compiler
模块,在 webpack 构建过程中,将template预编译成 render 函数。
babel-plugin-transform-vue-jsx
之后,就可以直接手写render函数。
说一下什么是Virtual DOM
介绍一下Vue中的Diff算法
-
首先,对比节点本身,判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换 -
如果为相同节点,进行patchVnode,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除) -
比较如果都有子节点,则进行updateChildren,判断如何对这些新老节点的子节点进行操作(diff核心)。 -
匹配时,找到相同的子节点,递归比较子节点
O(n^3)
降低值O(n)
,也就是说,只有当新旧children都为多个子节点时才需要用核心的Diff算法进行同层级比较。
key属性的作用是什么
说说Vue2.0和Vue3.0有什么区别
-
重构响应式系统,使用Proxy替换Object.defineProperty,使用Proxy优势:
-
可直接监听数组类型的数据变化 -
监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升 -
可拦截apply、ownKeys、has等13种方法,而Object.defineProperty不行 -
直接实现对象属性的新增/删除 -
新增Composition API,更好的逻辑复用和代码组织
-
重构 Virtual DOM
-
模板编译时的优化,将一些静态节点编译成常量 -
slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组件 -
模板中内联事件的提取并重用(原本每次渲染都重新生成内联函数) -
代码结构调整,更便于Tree shaking,使得体积更小
-
使用Typescript替换Flow
为什么要新增Composition API,它能解决什么问题
都说Composition API与React Hook很像,说说区别
-
不能在循环、条件、嵌套函数中调用Hook -
必须确保总是在你的React函数的顶层调用Hook -
useEffect、useMemo等函数必须手动确定依赖关系
-
声明在setup函数内,一次组件实例化只调用一次setup,而React Hook每次重渲染都需要调用Hook,使得React的GC比Vue更有压力,性能也相对于Vue来说也较慢 -
Compositon API的调用不需要顾虑调用顺序,也可以在循环、条件、嵌套函数中使用 -
响应式系统自动实现了依赖收集,进而组件的部分的性能优化由Vue内部自己完成,而React Hook需要手动传入依赖,而且必须必须保证依赖的顺序,让useEffect、useMemo等函数正确的捕获依赖变量,否则会由于依赖不正确使得组件性能下降。
SSR有了解吗?原理是什么?
-
有利于SEO:其实就是有利于爬虫来爬你的页面,因为部分页面爬虫是不支持执行JavaScript的,这种不支持执行JavaScript的爬虫抓取到的非SSR的页面会是一个空的HTML页面,而有了SSR以后,这些爬虫就可以获取到完整的HTML结构的数据,进而收录到搜索引擎中。 -
白屏时间更短:相对于客户端渲染,服务端渲染在浏览器请求URL之后已经得到了一个带有数据的HTML文本,浏览器只需要解析HTML,直接构建DOM树就可以。而客户端渲染,需要先得到一个空的HTML页面,这个时候页面已经进入白屏,之后还需要经过加载并执行 JavaScript、请求后端服务器获取数据、JavaScript 渲染页面几个过程才可以看到最后的页面。特别是在复杂应用中,由于需要加载 JavaScript 脚本,越是复杂的应用,需要加载的 JavaScript 脚本就越多、越大,这会导致应用的首屏加载时间非常长,进而降低了体验感。
更多详情查看 彻底理解服务端渲染-SSR原理 https://github.com/yacan8/blog/issues/30
结束
点个『在看』支持下
评论