前端面试Vue 高频原理篇+详细解答,还有105道vue面试题集合

- 缺点:对 SEO 搜索不太友好需要单独做配置,开发难度高一点需要专门的开发框架
iframe 实际上是
MPA
,但是可以实现SPA
的一些效果,但是本身由不少问题。
2.老生常谈之,为什么需要有这些 MVC/MVVM 模式?谈谈你对 MVC,MVVM 模式的区别,
目的:借鉴后端的思想,职责划分和分层
- Vue, React 不是真正意义上的 MVVM 更不是 MVC,两者核心只处理视图层
view
。
MVC模式
单向的数据,用户的每一步操作都需要重新请求数据库来修改视图层的渲染,形成一个单向的闭环。比如
jQuery+underscore+backbone
。
-
M:
model
数据存放层 -
V:
view
:视图层 页面 -
C:
controller
:控制器 js 逻辑层。
controller
控制层将数据层model层
的数据处理后显示在视图层view层
,同样视图层view层
接收用户的指令也可以通过控制层controller
,作用到数据层model
。所以MVC的缺点是视图层不能和数据层直接交互。
MVVM模式
隐藏了
controller
控制层,直接操控View
视图层和Model
数据层。
-
M:model 数据模型
-
V: view 视图模板
-
VM:view-model 视图数据模板(vue处理的层,vue 中的definedProperty 就是处理 VM 层的逻辑)
双向的数据绑定:
model
数据模型层通过数据绑定Data Bindings
直接影响视图层View
,同时视图层view
通过监听Dom Listener
也可以改变数据模型层model
。
-
数据绑定和DOM事件监听就是
viewModel
层Vue
主要做的事。也就是说:只要将数据模型层Model
的数据挂载到ViewModel
层Vue
就可以实现双向的数据绑定。 -
加上
vuex/redux
可以作为vue和react
的model
数据层。
var vm = new Vue()
复制代码
vm 就是
view-model
数据模型层,data:就是vmview-model
层所代理的数据。
- 综上两者的区别:MVC 的视图层和数据层交互需要通过控制层
controller
属于单向链接。MVVM 隐藏了控制层controller
,让视图层和数据层可以直接交互 属于双向连接。
小tip:响应式数据指的是数据发生了变化,视图可以更新就是响应式的数据
-
vue
中实现了一个definedReactive
方法,方法内部借用Object.definedProperty()
给每一个属性都添加了get/set
的属性。 -
definedReactive
只能监控到最外层的对象,对于内层的对象需要递归劫持数据。 -
数组则是重写的7个
push pop shift unshift reverse sort splice
来给数组做数据拦截,因为这几个方法会改变原数组 -
扩展:
// src\core\observer\index.js
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
// 准备给属性添加一个 dep 来依赖收集 Watcher 用于更新视图。
const dep = new Dep()
// some code
// observe() 用来观察值的类型,如果是属性也是对象就递归,为每个属性都加上get/set
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
// 这里取数据时依赖收集
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
// childOb 是对对像进行收集依赖
if (childOb) {
childOb.dep.depend()
//这里对数组和内部的数组进行递归收集依赖,这里数组的 key 和 value 都有dep。
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
// 属性发生改变,这里会通知 watcher 更新视图
}
})
}
复制代码
上面的 Dep(类) 是用来干嘛的?答:用来收集渲染的
Watcher
,Watcher
又是一个啥东西?答:watcher
是一个类,用于更新视图的
-
vue 没有对数组的每一项用
definedProperty()
来数据拦截,而是通过重写数组的方法push pop shift unshift reverse sort splice
。 -
手动调用 notify,通知 render watcher,执行 update
-
数组中如果有对象类型(
对象和数组
)的话会进行数据拦截。 -
所以通过修改数组下标和数组长度是不会进行数据拦截的,也就不会有响应式变化。例如
arr[0] = 1, arr.length = 2
都不会有响应式 -
扩展:
// src\core\observer\array.js
const methodsToPatch = [‘push’,‘pop’,‘shift’,‘unshift’,‘splice’,‘sort’,‘reverse’]
methodsToPatch.forEach(function (method) {
const original = arrayProto[method]
def(arrayMethods, method, function mutator (…args) {
const result = original.apply(this, args)
const ob = this.ob
let inserted
switch (method) {
case ‘push’:
case ‘unshift’:
inserted = args
break
case ‘splice’:
inserted = args.slice(2)
break
}
// 新增的类型再次观察
if (inserted) ob.observeArray(inserted)
// 手动调用 notify 派发更新
ob.dep.notify()
return result
})
})
复制代码
5.Vue 是怎样依赖收集的?(dep 和 Watcher 是什么关系)
tip:
Dep
是一个用来负责收集Watcher
的类,Watcher
是一个封装了渲染视图逻辑的类,用于派发更新的。需要注意的是Watcher 是不能直接更新视图的还需要结合Vnode经过patch()中的diff算法才可以生成真正的DOM
-
每一个属性都有自己的
dep
属性,来存放依赖的Watcher
,属性发生变化后会通知Watcher
去更新。 -
在用户获取(
getter
) 数据时 Vue 给每一个属性都添加了dep
属性来(collect as Dependency)收集Watcher
。在用户setting
设置属性值时dep.notify()
通知收集的Watcher
重新渲染。详情见上面的defineReactive()
-
Dep依赖收集类
其和Watcher类
是多对多双向存储的关系 -
每一个属性都可以有多个
Watcher 类
,因为属性可能在不同的组件中被使用。 -
同时一个
Watcher 类
也可以对应多个属性。
Vue中模板编译:其实就是将
template
转化成render
函数。说白了就是将真实的DOM(模板)
编译成虚拟dom(Vnode)
-
第一步是将
template 模板
字符串转换成ast 语法树
(parser 解析器),这里使用了大量的正则来匹配标签的名称,属性,文本等。 -
第二步是对 AST 进行静态节点
static
标记,主要用来做虚拟 DOM 的渲染优化(optimize优化器),这里会遍历出所有的子节点也做静态标记 -
第三步是 使用
ast语法树
重新生成render 函数
代码字符串 code。(codeGen 代码生成器)
为什么要静态标记节点,如果是静态节点(没有绑定数据,前后不需要发生变化的节点)那么后续就不需要 diff 算法来作比较。
-
vue 中的生命周期钩子只是一个回调函数,在创建组件实例化的过程中会调用对应的钩子执行。
-
使用
Vue.mixin({})
混入的钩子或生命周期中定义了多个函数,vue 内部会调用mergeHook()
对钩子进行合并放入到队列中依次执行 -
扩展
// src\core\util\options.js
function mergeHook (
parentVal: ?Array,
childVal: ?Function | ?Array
): ?Array {
const res = childVal
? parentVal
-
? parentVal.concat(childVal) // 合并
-
Array.isArray(childVal)
? childVal
-
[childVal]
-
parentVal
return res
-
? dedupeHooks(res)
- res
}
复制代码
8.老生常谈之 vue 生命周期有哪些,一般在哪里发送请求?
-
beforeCreate
: 刚开始初始化 vue 实例,在数据观测observer
之前调用,还没有创建data/methods
等属性 -
created
: vue 实例初始化结束,所有的属性已经创建。 -
beforeMount
: 在 vue 挂载数据到页面上之前,触发这个钩子,render 函数此时被触发。 -
mounted
: el 被 创建的vm.$el
替换,vue 初始化的数据已经挂载到页面之上,这里可以访问到真实的 DOM。一般会在这里请求数据。 -
beforeUpdate
: 数据更新时调用,也就是在虚拟 dom 重新渲染之前。 -
updated
: 数据变化导致虚拟 dom 发生重新渲染之后发生。 -
beforeDestroy
: 实例销毁之前调用该钩子,此时实例还在。vm.$destroy
触发两个方法。 -
destroyed
: Vue 实例销毁之后调用。所有的事件监听都会被接触。
请求数据要看具体的业务需求决定在哪里发送
ajax
-
使用场景:用于抽离一个公共的业务逻辑实现复用。
-
实现原理:调用
mergeOptions()
方法采用策略模式针对不同的属性合并。混入的数据和组件的数据有冲突就采用组件本身的。 -
Vue.mixin({})
缺陷,1.可能会导致混入的属性名和组件属性名发生命名冲突;2. 数据依赖的来源问题 -
扩展
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
// some code
if (!child._base) {
if (child.extends) {
parent = mergeOptions(parent, child.extends, vm)
}
if (child.mixins) {
for (let i = 0, l = child.mixins.length; i < l; i++) {
parent = mergeOptions(parent, child.mixins[i], vm)
}
}
}
// 递归遍历合并组件和混入的属性
const options = {}
let key
for (key in parent) {
mergeField(key)
}
for (key in child) {
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
function mergeField (key) {
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
复制代码
10.老生常谈之 vue 组件中的data 为什么必须是一个函数?
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-XMYVTuyy-1715893750841)]
[外链图片转存中…(img-ZMKi4RQV-1715893750841)]
[外链图片转存中…(img-3iTnbf5h-1715893750841)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!




更多推荐
所有评论(0)