基础
基础
1. 谈谈你对vue的理解(vue是什么?)
考察你对vue的理解,以及你对前端框架的理解 https://github.com/haizlin/fe-interview/issues/223
渐进式框架
声明式框架 ---> 组件系统 ---> 客户端路由 ---> 状态管理 ---> 构建工具
(1) 声明式框架
Vue 的核心特点,用起来简单。那们就有必要知道命令式和声明式的区别!
- 早在JQ 的时代编写的代码都是命令式的,命令式框架重要特点就是关注过程
- 声明式框架更加关注结果。命令式的代码封装到了 Vuejs 中,过程靠 vuejs 来实现
(2) MVVM模式
说起MVVM,就必须提一下MVC,MVC是一种设计模式,它将应用程序分为三个核心部件:模型(Model)、视图(View)和控制器(Controller)。
MVC模式:Backbone + underscore + jquery
对于前端而言,数据变化无法同步到视图中。需要将逻辑聚拢在控制器层
- Model(模型): 数据模型,它主要保存应用程序的数据和业务逻辑。
- View(视图): 视图层,它主要用来将数据模型转化为UI展示出来。
- Controller(控制器): 控制器,它用来控制应用程序的数据流向,将数据从模型层交给视图层进行展示。
MVVM模式:映射关系的简化(隐藏 controller)
虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也是借鉴了MVVM的这种思想。典型的MVVM是不能跳过数据和视图层的绑定的,但是vue可以通过ref来操作数据,所以在文档中经常会使用 vm(ViewModel的缩写) 这个变量名来表示 Vue 实例。
它们之间的具体关系如下:
- MVVM(Model-View-ViewModel): MVVM可以看作是一种特殊的MVC模式,它将Controller改为了ViewModel。ViewModel负责连接Model和View,使得当Model发生变化时,ViewModel可以自动更新View,反之亦然。
- MVVM与MVC的区别: MVVM与MVC最大的区别在于,它采用双向数据绑定,使得View和Model之间的数据同步变得更加简单和自动。
- MVVM的优点: MVVM的主要优点是数据双向绑定,使得开发人员可以更加专注于业务逻辑的开发,而不需要手动操作DOM。
- MVVM的缺点: MVVM的主要缺点是学习成本较高,需要理解双向数据绑定的工作原理,以及如何使用Vue的指令和组件。
- MVVM的应用场景: MVVM适用于需要大量数据绑定的场景,如单页应用(SPA)。
- MVVM的框架: Vue、Angular、React等。
- MVVM的原理: MVVM的原理是通过数据劫持和发布订阅模式实现数据双向绑定的。
(4) 采用虚拟DOM
传统更新页面,拼接一个完整的字符串 innerHTML 全部重新渲染,添加虚拟DOM 后,可以比较新旧虚拟节点,找到变化在进行更新。虚拟 DOM 就是一个对象,用来描述真实 DOM 的
什么是虚拟dom?
虚拟 DOM(Virtual DOM)是前端开发中的一种技术,它通过在内存中创建一个虚拟的 DOM 树来描述真实的 DOM 树,从而实现高效的 DOM 操作。
(5) 区分编译时(打包)和运行(浏览器)时
- Vue 的渲染核心就是调用渲染(render)方法将虚拟 DOM 渲染成真实 DOM(缺点就是虚拟 DOM 编写麻烦)
- 专门写个编译时可以将模板编译成虚拟 DOM(在构建的时候进行编译性能更高,不需要再运行的时候进行编译)
(3) 组件化
- 什么是组件化一句话来说就是把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式,在 Vue 中每一个 .vue 文件都可以视为一个组件
- 组件化的优势
- 降低整个系统的耦合度,在保持接口不变的情况下,我们可以替换不同的组件快速完成需求,例如输入框,可以替换为日历、时间、范围等组件作具体的实现
- 调试方便,由于整个系统是通过组件组合起来的,在出现问题的时候,可以用排除法直接移除组件,或者根据报错的组件快速定位问题,之所以能够快速定位,是因为每个组件之间低耦合,职责单一,所以逻辑会比分析整个系统要简单
- 提高可维护性,由于每个组件的职责单一,并且组件在系统中是被复用的,所以对代码进行优化可获得系统的整体升级
2. Vue 有哪些 核心特性?
(1)数据驱动(MVVM)
MVVM表示的是 Model-View-ViewModel
- Model: 模型层,负责处理业务逻辑以及和服务器端进行交互
- View: 视图层:负责将数据模型转化为UI展示出来,可以简单的理解为HTML页面
- ViewModel: 视图模型层,用来连接Model和View,是 Model 和 View 之间的通信桥梁
(3)指令
- 条件渲染指令 v-if
- 列表渲染指令 v-for
- 属性绑定指令 v-bind
- 事件绑定指令 v-on
- 双向数据绑定指令v-model
3. 说说你对 SPA 单页面的理解,它的优缺点分别是什么?
基本概念
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS 。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。 SPA(single-page application)单页应用,默认情况下我们编写Vue、React 都只有一个htm1 页面,并且提供一个挂载点,最终打包后会再此页面中引入对应的资源。(页面的渲染全部是由」 动态进行渲染的)。切换页面时通过监听路由变化,染对应的页面 client side Rendering,客户端渲染 CSR
MPA(Multi-page application):多页应用,多个 htm1 页面。每个页面必须重复加载,js,css 等相关资源。(服务端返回完整的 html,同时数据也可以再后端进行获取一并返回“模板引擎”)。多页应用跳转需要整页资源刷新。Server side Rendering,服务器端渲染 SSR
优点:
- 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
- 基于上面一点,SPA 相对对服务器压力小;
- 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
缺点:
- 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
- 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
- SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。
解决 SPA应用的 SEO
- 静态页面预渲染(Static Site Generation)SSG,在构建时生成完整的 html 页面。(就是在打包的时候先将页面放到浏览器中运行一下,将 HTML 保存起来),仅适合静态页面网站。变化率不高的网站
- SSR + CSR 的方式,首屏采用服务端渲染的方式,后续交互采用客户端染方式,Nuxtis
vue 的虚拟 DOM?
- Virtual DOM 就是用 js 对象来描述真实 DOM,是对真实 DOM 的抽象,由于直接操作 DOM 性能低,但是 js 层的操作效率高,可以将 DOM 操作转化成对象操作,最终通过 diff 算法比对差异进行更新 DOM(减少了对真实 DOM 的操作)。
- 虚拟 DOM 不依赖真实平台环境从而也可以实现跨平台
是怎么生成的?
- 在 vue 中我们常常会为组件编写模板-template
- 这个模板会被编译器编译为渲染函数-render
- 在接下来的挂载过程中会调用 render函数,返回的对象就是虚拟 dom
- 会在后续的 patch 过程中进一步转化为 真实 dom。
VDOM 如何做 diff 的?
- 挂载过程结束后,会记录第一次生成的 VDOM-oldVnode
- 当响应式数据发生变化时,将会引起组件重新 render,此时就会生成新的VDOM-newVnode
- 使用 oldVnode 与 newnode 做 diff 操作,将更改的部分应到真实 DOM 上,从而转换为最小量的 dom操作,高效更新视图。
如何实现一个虚拟DOM?说说你的思路
你了解vue的diff算法吗?
4. v-show 与 v-if 有什么区别?
- 区别:
- v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
- v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
- 使用场景
- v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;
- v-show 则适用于需要非常频繁切换条件的场景。
说说组件化和模块化的区别?
- 组件化: 从 UI 的角度出发,把页面拆分成多个可以复用的独立且相对独立的模块,每个模块之间相互独立,但可以相互组合,复用。
- 模块化: 从代码逻辑的角度出发,把复杂程序拆分成多个独立的模块,每个模块负责实现特定的功能,相互独立,可以相互引用。
既然 Vue 通过数据劫持可以精准探测数据变化,为什么还需要虚拟 DOM 进行 diff 检测差异?
在 vue1 版本中就只有 watcher,没有采用 diff 算法,所以这样会导致非常的耗性能, Vue2 内部设计原因导致,vue 设计的是每个组件一个 watcher(渲染函数 watcher),没有采用一个属性对应-个 watcher。这样会导致大量 watcher 的产生而且浪费内存,如果粒度过低也无法精准检测变化。所以采用diff 算法 + 组件级 watcher。
19. 说一下你对响应式数据的理解?(Vue2 和 Vue3 的响应式原理是什么?)
数组和对象类型当值变化时如何劫持到?
对象内部通过 defineReactive
方法,使用 object.defineProperty
将属性进行劫持(只会劫持已经存在的属性),数组则是通过重写数组方法来实现。多层对象是通过递归来实现劫持。 vue3 则采用 proxy
vue2 处理缺陷
- 在 vue2 的时候使用 defineProperty 来进行数据的劫持,需要对属性进行重写添加 getter 及 setter 性能差。
- 当新增属性和删除属性时无法监控变化。需要通过 delete 实现,就是改变 data 的对象时,vue 无法劫持到,需要通过 delete 实现。
- 数组不采用 defineProperty 来进行劫持(浪费性能,对所有索引进行劫持会造成性能浪费)需要对数组单独进行处理。
- 对于 ES6 中新产生的 Map、Set 这些数据结构不支持。
3 vue2 与 vue3 实现对比
Vue 中如何检测数组变化?
5. Class 与 Style 如何动态绑定?
Class 可以通过对象语法和数组语法进行动态绑定: https://github.com/haizlin/fe-interview/issues/437
/** 对象语法 */
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
data: {
isActive: true,
hasError: false
}
/** 数组语法 */
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
Style 也可以通过对象语法和数组语法进行动态绑定:
/** 对象语法 */
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
/** 数组语法 */
<div v-bind:style="[styleColor, styleSize]"></div>
data: {
styleColor: {
color: 'red'
},
styleSize:{
fontSize:'23px'
}
}
6. 怎样理解 Vue 的单向数据流?
所有的 prop 都使得其父子 prop 之间形成了一个单向绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改父组件的值时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。
7. computed 和 watch 的区别和运用的场景? 底层实现有什么区别?分别在什么场景下使用?
- 区别
- computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
- watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
- 运用场景:
- 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
- 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
为什么白屏加载时间长?
因为在打包后的 index.html 里面,打包后的 js 脚本在最下面,所以首先是加载一个空的 div,然后再去加载哪些js脚本,这就会导致白屏时间过长。