这两天在看红宝书的对象和原型部分,今天又看到了Vue的面试题里的Vue响应原理MVVM。简单记录一下现在的理解,未必完全,仅作为自己逐渐探索MVVM和MVC内在区别的记录。
Object对象有两种属性,一种是数据属性(),一种是访问器属性(getter和setter)。正常我们设置值都是设置数据属性的,而访问器属性是对外不可见的。
在Vue中,当我们把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。
对外来说,我们是看不见传入的对象被增加了getter和setter属性的,但是就是因为getter和setter中的设置代码,在每次setter和getter时都会通知Vue变更。每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
Vue组件是否更新,是看 watcher 实例是不是接收到通知,而通知 watcher的就是一开始Object.defineProperty()重写的setter方法。此处因为JavaScript的限制,无法追踪到对象的property添加和移除,以及无法追踪到数组length的变化和下标修改数组的值。
**Vue 无法追踪生效的情况**
对象
**Vue 无法检测 property 的添加或移除。
**`var vm = new Vue({
data:{
a:1
}
})
// `vm.a` 是响应式的
vm.b = 2
// `vm.b` 是非响应式的`
解决办法:使用this.$set(对象|数组,属性|下标,newvalue)
数组
1、直接通过下标改变数组值,不会触发更新
例如:items: ['a', 'b', 'c']
this.item[0] = 'ss' 不会触发更新
解决办法:使用this.$set(对象|数组,属性|下标,newvalue)
2、改变数组的length属性
item.length = 2
虽然数组被截取了一个元素,发生了改变但也不会触发更新。
解决办法:
使用splice(indexOfItem, 1, newValue)
|