关于vue中数组与对象更新检测的问题

(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方法,进行赋值的同时,还会将这些数据变成响应式数据。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容