1、前言
我们都是知道我们可以通过重写原型Object.defineProperty来实现数据的监听,我们的vue2.x也是通过这个来实现数据双向绑定的核心功能的,也是围绕虚拟节点和数据绑定等核心的功能来实现一些框架比如说 Vue 组件库等框架。
那么Vue2也存在一些问题,官方的解释是性能上大于用户体验所以对数组的监听情况会存在问题。
2、Object.defineProperty
1、通过索引访问或设置对应元素的值时,可以触发 getter 和 setter 方法
2、通过 push 或 unshift 会增加索引,对于新增加的属性,需要再手动初始化才能被 observe
3、通过 pop 或 shift 删除元素,会删除并更新索引,也会触发 setter 和 getter 方法
所以,Object.defineProperty
是有监控数组下标变化的能力的,只是在 vue2.x 放弃了这个特性。
当然,在 Vue3.0 中则对这方面做了很大程度的改进,采用 Proxy
替代了 Object.defineProperty
3、那我们该如何解决vue2中存在的问题呢?
关于这个问题,我们可以拆分开来讨论,同时针对vue能够监听的场景和无法监听的场景进行讨论,并给出对应的解决方案:
监听数组的变化:
1)vue 能够监听数组变化的场景
通过赋值的形式改变正在被监听的数组;
通过 splice(index, num, val) 的形式改变正在被监听的数组;
通过数组的 push 的形式改变正在被监听的数组;
2)vue 无法监听数组变化的场景
通过数组索引改变数组元素的值;
改变数组的长度;
3)vue 无法监听数组变化的解决方案
this.$set(arr, index, newVal);
通过 splice(index,num,val);
使用临时变量作为中转,重新赋值数组;
监听对象的变化:
1)vue 能够监听对象变化的场景
通过直接赋值的场景;
e.g:watchObj = {name:"zyk"}
2)vue 无法监听对象变化的场景
对象的增加、删除、修改无法被vue监听到
3)vue 无法监听对象变化的解决方案
使用 this.$set(object, key, value)(vue 无法监听 this.$set 修改原有属性)
使用 Object.assign(),直接赋值的原理;(深拷贝,推荐使用)
关于 Object.assign() — MDN 方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。
其实使用 Object.assign() 也是基于深拷贝的实现原理