(1)数组更新检测
vue包含一些数组变异方法检测:push、pop、shift、unshift、reverse、sort、splice这些方法会导致数组的变异,也就是会替换调用这些方法的原有数组,vue对于这些方法做了劫持,在新的方法中手动触发了一次更新。
然而有些非变异数组方法不会修改原数组:filter、concat、slice这些操作并不会修改原数组,这些操作都会返回新的数组,因此可以对原有数组重新赋值,从而使得vue检测到数组的更新,如:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
由于javascript的限制,Vue 不能检测以下变动的数组:
- 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:vm.items.length = newLength
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// 也可以使用vm.$set
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
为了解决第二类问题,你可以使用 splice:
vm.items.splice(newLength)
(2)对象更新检测
还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。
总结
无论对于数组还是对象,在javascript中都是存储在堆内存中,保存的其实是一个指向堆的指针,因此在对数组进行非变异方法,或则直接给对象添加或删除属性时,该指针并没有改变。从vue源码中可知,vue的双向绑定的核心其实就是使用的defineProperty,在给已创建的实例进行set操作时,会触发所有依赖该实例的其它实例的更新。而这些操作并没有修改原有的实例,没有触发set操作,从而也就不会触发其它包括视图的更新。而vue的set方法,进行赋值的同时,还会将这些数据变成响应式数据。