难度级别:中高级及以上 提问概率:55%
这道题面试官会这样描述,比如有这样一个场景,一个对象里有name属性,可以正常显示在页面中。但后续动态添加了一个age属性,通过调试打印发现对象里的age属性已经添加了上了,但试图中却没有展示出来,请你说一说原因。
在Vue项目中一旦发现试图没有更新,首先要排查的就是数据是否已更新,不过本题已经帮助排查过了,那么问题很可能出现在Vue针对数据变更的响应式监听上。在Vue组件中,我们会提前定义一些data数据依赖,Vue在做初始化双向数据绑定的时候,会针对数据依赖的属性进行响应式监听,然后通过Vue指令将template模板中的变量与data数据依赖绑定起来,主要核心原理使用的就是Object的defineProperty方法。那么回归到本题上,响应式监听核心代码就像这样
Javascript代码:
<script>
cosnt people = {
name: '张三'
};
Object.defineProperty(people, 'name', {
get() {
return val;
},
set(newVal) {
if (newVal !== val) {
val = newVal;
}
}
})
setTimeout(() => {
people['age'] = 25;
}, 3000)
</script>
因为在Vue初始实例的时候,defineProperty方法针对的是对象属性,所以属性新增后,新属性并不能被监听到,也就是无法被响应到试图模板中了。那么有哪些方法可以达到更新的效果呢?我们一起来看一下。
首先最简单粗暴的方案就是使用$forceUpdate()方法,进行组件强制更新,它其实是触发了组件的update方法,并不会使组件整体再更新一遍,也就是created、mounted这些生命周期并不会被触发。
另一种方案是使用Vue.set()方法,这个方法接收3个参数,分别是要修改的对象、属性和属性值。set方法首先确认当前传入的对象是否属于响应式对象,如果不是响应式对象,则只是单纯的为目标对象赋值即可,如果是响应式对象,这里就需要调用核心方法defineReactive,这个方法内部则是再次执行Object.defineProperty方法,将新增的属性添加到响应式对象中去。这还没有结束,新的响应属性添加完成了,在源码文件\node_modules\vue\src\core\observer\index.js中,通过ob.dep.notify()手动更新试图即可。
刷题思考
这道题是Vue2中的一道经典面试题,关于对象动态添加属性视图无法更新的问题,在面试的时候,要把我住两点,第一就是讲述自己遇到的项目场景和解决方案,而这也只是基础回答,将问题出现的原因和set()方法的原理描述清除,才能算作标准回答。
类似考点
Vue2其实还有很多经典的问题,虽然在Vue3中得到了解决,但肯定还是有面试官会问类似的问题,例如请你说一说,Vue2监听数组变化的时候会遇到哪些问题?例如请你说一说,$nextTick的使用场景有哪些?