小编在群里看到一句话,说三件套加 vue 就能够找到实习,三件套预计说的是 HTML+JavaScript+CSS,但还有这坏事?这可不得连忙把 vue 面试题安顿上。实不实习不重要,次要是想学习哈哈哈哈(加狗头)。
也有小伙伴私信小编有没有 vue 的面试题,看来之前的前端面试套餐:Vue 面试题总结 +JavaScript 前端经典面试题 +100 道 CSS 面试题满足不了大家呀,小编又整顿了一套 vue 面试题汇合,须要的小伙伴间接点击这里喔
面试题篇
1. 陈词滥调之,MPA/SPA 的了解,优缺点是什么?
MPA
多页面利用。
- 形成:有多个页面
html
形成, - 跳转形式:页面的跳转是从一个页面到另一个页面
- 刷新的形式:全页面刷新
- 页面数据跳转:依赖
URL/cookie/localStorage
- 跳转后的资源
会从新加载
- 长处:对 SEO 比拟敌对,开发难度低一点。
SPA
单页面利用
- 页面组成:由一个外壳页面包裹,多个页面 (组件) 片段组成
- 跳转形式:在外壳页面中跳转,将片段页面 (组件) 显示或暗藏
- 刷新形式:页面片段的部分刷新
- 页面的数据跳转:组件间的传值比拟容易
- 跳转后的资源
不会从新加载
- 毛病:对 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
,让视图层和数据层能够间接交互 属于双向连贯。
3. 说一下对 Vue 中响应式数据的了解
小 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
是一个类,用于更新视图的
4. Vue 是怎么检测数组的变动的?
- 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 类
也能够对应多个属性。
6. Vue 中的模板编译
Vue 中模板编译:其实就是将
template
转化成render
函数。说白了就是将实在的DOM(模板)
编译成虚构dom(Vnode)
- 第一步是将
template 模板
字符串转换成ast 语法树
(parser 解析器),这里应用了大量的正则来匹配标签的名称,属性,文本等。 - 第二步是对 AST 进行动态节点
static
标记,次要用来做虚构 DOM 的渲染优化(optimize 优化器),这里会遍历出所有的子节点也做动态标记 - 第三步是 应用
ast 语法树
从新生成render 函数
代码字符串 code。(codeGen 代码生成器)
为什么要动态标记节点,如果是动态节点 (没有绑定数据,前后不须要发生变化的节点) 那么后续就不须要 diff 算法来作比拟。
7. 生命周期钩子实现原理
- vue 中的生命周期钩子只是一个回调函数,在创立组件实例化的过程中会调用对应的钩子执行。
- 应用
Vue.mixin({})
混入的钩子或生命周期中定义了多个函数,vue 外部会调用mergeHook()
对钩子进行合并放入到队列中顺次执行 - 扩大
// src\core\util\options.js
function mergeHook (
parentVal: ?Array<Function>,
childVal: ?Function | ?Array<Function>
): ?Array<Function> {
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
9.Vue.mixin({})的应用场景和原理
- 应用场景:用于抽离一个公共的业务逻辑实现复用。
- 实现原理:调用
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 为什么必须是一个函数?
- 这和 js 自身机制相干,
data
函数中返回的对象援用地址不同,就能保障不同组件之间的数据不互相净化。 Vue.mixin()
中如果混入data
属性,那么data
也必须是一个函数。因为Vue.mixin()
也能够多处应用。- 实例中
data
能够是一个对象也能够是一个函数,因为咱们一个页面个别只初始化一个 Vue 实例(单例)
11. 陈词滥调之 vue 中 vm.$nextTick(cb)实现原理和场景
- 场景:
在 dom 更新循环完结后调用,用于获取更新后的 dom 数据
- 实现原理:
vm.$nextTick(cb)
是一个异步的办法为了兼容性做了很多降级解决顺次有promise.then,MutationObserver,setImmediate,setTimeout
。在数据批改后不会马上更新视图,而是通过set
办法 notify 告诉Watcher
更新,将须要更新的Watcher
放入到一个异步队列中,nexTick
的回调函数就放在Watcher
的前面,期待主线程中同步代码执行借宿而后顺次清空队列中,所以vm.nextTick(callback)
是在dom
更新完结后执行的。
下面将对列中
Watcher
顺次清空就是vue 异步批量更新的原理
。提一个小思考:为什么不间接应用setTimeout
代替?因为setTimeout
是一个宏工作,宏工作多性能也会差。
12. 陈词滥调之 watch 和 computed 区别
computed
外部就是依据Object.definedProperty()
实现的computed
具备缓存性能,依赖的值不发生变化,就不会从新计算。watch
是监控值的变动,值发生变化时会执行对应的回调函数。computed
和watch
都是基于Watcher 类
来执行的。
computed
缓存性能依附一个变量dirty
,示意值是不是脏的默认是true
,取值后是false
,再次取值时dirty
还是false
间接将还是上一次的取值返回。
// src\core\instance\state.js computed 取值函数
function createComputedGetter (key) {return function computedGetter () {const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {if (watcher.dirty) { // 判断值是不是脏 dirty
watcher.evaluate()}
if (Dep.target) {watcher.depend()
}
return watcher.value
}
}
}
// src\core\instance\state.js watch 实现
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Object
): Function {
const vm: Component = this
if (isPlainObject(cb)) {return createWatcher(vm, expOrFn, cb, options)
}
options = options || {}
options.user = true
// 实例化 watcher
const watcher = new Watcher(vm, expOrFn, cb, options)
if (options.immediate) {const info = `callback for immediate watcher "${watcher.expression}"`
pushTarget()
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)
popTarget()}
return function unwatchFn () {watcher.teardown()
}
}
Vue 面试题汇合
面试光看这 12 道题怎么够呢?小编把 vue 面试题整顿成了一个汇合共有 105 道题目,不多但经典哦。
- vue.js 的两个外围是什么?
- vue 的双向绑定的原理是什么?
- vue 生命周期钩子函数有哪些?
- 请问 v-if 和 v-show 有什么区别?
- vue 罕用的修饰符
- nextTick
- 什么是 vue 生命周期
- 数据响应(数据劫持)
- virtual dom 原理实现
- Proxy 相比于 defineProperty 的劣势
- vuex
- vue 中 key 值的作用
- Vue 组件中 data 为什么必须是函数?
- v-for 与 v-if 的优先级
- 说出至多 4 种 vue 当中的指令和它的用法
- vue 中子组件调用父组件的办法
- vue 中父组件调用子组件的办法
- vue 页面级组件之间传值
- 说说 vue 的动静组件。
- keep-alive 内置组件的作用
- 递归组件的用法
- 怎么定义 vue-router 的动静路由?怎么获取传过来的值?
- vue-router 有哪几种路由守卫?
- $route 和 $router 的区别是什么?
- vue-router 响应路由参数的变动
- vue-router 传参
- 不必 Vuex 会带来什么问题?
- vuex 有哪几种属性?
- vuex 的 State 个性是?
- vuex 的 Getter 个性是?
完整版的 vue 汇合 PDF 材料间接点击这里就能够支付了哦,前端面试套餐点击这能够支付,也能分割小编,说不定你想要的我这正有呢。
结束语
无论是几件套加 vue 还是什么,前端找工作该学的知识点、面试该问到的面试题一个不会落下,加油小伙伴们!喜爱这篇文章的留下你们的“点赞 + 评论”,给小编充充能量。