Vue 常见面试题汇总
Vue 的优缺点
优点
1、创建单页面应用的轻量级Web应用框架
2、简单易用
3、双向数据绑定
4、组件化的思想
5、虚拟DOM
6、数据驱动视图
7、前后端分离
缺点
1、Vue在开发多页应时不够灵活,需要配置多入口
2、不支持IE8
SPA的理解
SPA是 Single-Page-Application 的缩写,翻译过来就是单页应用。在WEB页面初始化时一同加载Html、Javascript、Css。一旦页面加载完成,SPA不会因为用户操作而进行页面重新加载或跳转,取而代之的是利用路由机制实现Html内容的变换。
优点
1、良好的用户体验,内容更改无需重载页面
2、SPA相对服务端压力更小
3、前后端职责分离,架构清晰
缺点
1、由于前端渲染,搜索引擎不会解析JS,只能抓取首页未渲染的模板,不利于SEO
2、单页面应用,在加载页面的时候将JavaScript、CSS统一加载,所以首次加载耗时更多
3、单页面应用需在一个页面显示所有的内容,默认不支持浏览器的前进后退(前端路由机制解决了该窘境,Hash模式中Hash变化会被浏览器记录,History模式利用 H5 新增的pushState和replaceState方法可改变浏览器历史记录栈)
MVVM的理解
MVVM是Model-View-ViewModel的缩写。Model 代表数据层,可定义修改数据、编写业务逻辑。View 代表视图层,负责将数据渲染成页面。ViewModel 负责监听数据层数据变化,控制视图层行为交互,简单讲,就是同步数据层和视图层的对象。ViewModel 通过双向绑定把 View 和 Model 层连接起来,且同步工作无需人为干涉,使开发人员只关注业务逻辑,无需频繁操作DOM,不需关注数据状态的同步问题。
对象
遍历对象,通过Object.defineProperty为每个属性添加 getter 和 setter,进行数据劫持。getter 函数用于在数据读取时进行依赖收集,在对应的 dep 中存储所有的 watcher;setter 则是数据更新后通知所有的 watcher 进行更新。
核心源码
function defineReactive(obj, key, val, shallow) {
// 实例化一个 dep, 一个 key 对应一个 dep
const dep = new Dep()
// 获取属性描述符
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
// 通过递归的方式处理 val 为对象的情况,即处理嵌套对象
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
// 拦截obj.key,进行依赖收集
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
// Dep.target 是当前组件渲染的 watcher
if (Dep.target) {
// 将 dep 添加到 watcher 中
dep.depend()
if (childOb) {
// 嵌套对象依赖收集
childOb.dep.depend()
// 响应式处理 value 值为数组的情况
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
// 获取旧值
const value = getter ? getter.call(obj) : val
// 判断新旧值是否一致
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
if (getter && !setter) return
// 如果是新值,用新值替换旧值
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
// 新值做响应式处理
childOb = !shallow && observe(newVal)
// 当响应式数据更新,依赖通知更新
dep.notify()
}
})
}
数组
用数组增强的方式,覆盖原属性上默认的数组方法,保证在新增或删除数据时,通过 dep 通知所有的 watcher 进行更新。
核心源码
const arrayProto = Array.prototype
// 基于数组原型对象创建一个新的对象
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
methodsToPatch.forEach(function (method) {
const original = arrayProto[method]
// 分别在 arrayMethods 对象上定义7个方法
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)
// 数据无论是新增还是删除都进行派发更新
ob.dep.notify()
return result
})
})
单向数据流的理解
我们经常说 Vue 的双向绑定,其实是在单向绑定的基础上给元素添加 input/change 事件,来动态修改视图。Vue 组件间传递数据仍然是单项的,即父组件传递到子组件。子组件内部可以定义依赖 props 中的值,但无权修改父组件传递的数据,这样做防止子组件意外变更父组件的状态,导致应用数据流向难以理解。
如果在子组件内部直接更改prop,会遇到警告处理。
以下为2种定义依赖props中的值
1、通过 data 定义属性并将 prop 作为初始值
<script>
export default {
props: ['userName'],
data() {
return {
name: this.userName
}
}
}
</script>
2、 用 computed 计算属性去定义依赖 prop 的值
<script>
export default {
props: ['userName'],
computed: {
helloName() {
return "hello" + this.userName
}
}
}
</sciprt>
响应式原理
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
组件中的data为什么是一个函数
数据以函数返回值形式定义,当每复用一次组件,就会返回一份新的data。即给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。对象在栈中存储的都是地址,函数的作用就是属性私有化,保证组件修改自身属性时不会影响其他复用组件。
生命周期
生命周期 描述
beforeCreate vue实例初始化后,数据观测(data observer)和事件配置之前。data、computed、watch、methods都无法访问。
created vue实例创建完成后立即调用 ,可访问 data、computed、watch、methods。未挂载 DOM,不能访问 、ref。
beforeMount 在 DOM 挂载开始之前调用。
mounted vue实例被挂载到 DOM。
beforeUpdate 数据更新之前调用,发生在虚拟 DOM 打补丁之前。
updated 数据更新之后调用。
beforeDestroy 实例销毁前调用。
destroyed 实例销毁后调用 。
调用异步请求可在created、beforeMount、mounted生命周期中调用,因为相关数据都已创建。在不涉及到DOM操作时,最好的选择是在created中调用。
- 点赞
- 收藏
- 关注作者
评论(0)