面试题答案
一键面试1. 使用Object.defineProperty实现Vue数据响应式的原理
通过 Object.defineProperty
方法可以给对象的属性定义 getter 和 setter 函数。在Vue中,会遍历数据对象的所有属性,使用 Object.defineProperty
将这些属性转换为“响应式”数据。
当获取属性值时,会触发 getter 函数,此时可以收集依赖(例如哪些视图依赖了该数据)。当属性值发生变化时,会触发 setter 函数,在 setter 函数中通知依赖(视图)进行更新,从而实现数据的响应式。
示例代码如下:
let data = {
name: '张三'
};
let vm = {};
Object.defineProperty(vm, 'name', {
get() {
console.log('获取name属性');
return data.name;
},
set(newValue) {
console.log('设置name属性为', newValue);
data.name = newValue;
// 这里可以触发视图更新逻辑
}
});
2. 这种方式存在的缺陷
- 新增和删除属性无法监听:使用
Object.defineProperty
定义的响应式数据,在对象创建时就已经确定了其属性。如果在之后新增属性,例如obj.newProp = 'new value'
,Vue无法自动将newProp
变成响应式数据,需要使用Vue.set
方法来处理。同理,删除属性(delete obj.oldProp
)时,也不会触发视图更新,除非手动处理。 - 数组更新检测问题:对于数组,
Object.defineProperty
无法监听数组的变化。例如arr.push('new item')
这样的操作,Vue无法检测到数组的更新从而更新视图。Vue通过重写数组的原型方法(如push
、pop
、shift
等)来解决这个问题,但这并不是Object.defineProperty
本身的能力。 - 深度监听问题:对于多层嵌套的对象,需要递归遍历所有层级的属性,使用
Object.defineProperty
进行设置,这会带来性能问题,而且代码实现较为复杂。