☀️Vue2.0为什么不能检查数组的变化?又该如何解决?


在这里插入图片描述


前言

我们都知道,Vue2.0对于响应式数据的实现有一些不足:

  • 无法检测数组/对象的新增
  • 无法检测通过索引改变数组的操作。
分析
  • 无法检测数组/对象的新增?

    Vue检测数据的变动是通过Object.defineProperty实现的,所以无法监听数组的添加操作是可以理解的,因为是在构造函数中就已经为所有属性做了这个检测绑定操作。

  • 无法检测通过索引改变数组的操作。即vm.items[indexOfItem] = newValue?

    官方文档中对于这两点都是简要的概括为“由于JavaScript的限制”无法实现,而Object.defineProperty是实现检测数据改变的方案,那这个限制是指Object.defineProperty吗?

思考
vm.items[indexOfItem] = newValue真的不能被监听么?

Vue对数组的7个变异方法(push、pop、shift、unshift、splice、sort、reverse)实现了响应式。这里就不做测试了。我们测试一下通过索引改变数组的操作,能不能被监听到。

遍历数组,用Object.defineProperty对每一项进行监测

function defineReactive(data, key, value) {
	 Object.defineProperty(data, key, {
		 enumerable: true,
		 configurable: true,
		 get: function defineGet() {
			 console.log(`get key: ${key} value: ${value}`)
			 return value
		 },
		 set: function defineSet(newVal) {
			 console.log(`set key: ${key} value: ${newVal}`)
			 value = newVal
		 }
	 })
}
 
function observe(data) {
	Object.keys(data).forEach(function(key) {
		defineReactive(data, key, data[key])
	})
}
 
let arr = [1, 2, 3]
observe(arr)

image-20210607020953993

测试说明

通过索引改变arr[1],我们发现触发了set,也就是Object.defineProperty是可以检测到通过索引改变数组的操作的,那Vue2.0为什么没有实现呢?是尤大能力不行?这肯定毋庸置疑。那他为什么不实现呢?

后续

后来我在网上找的时候发现了这个。🌀🔥这是github上,一位开发小哥对尤大提到问题。

image-20210607021557820


小结:原来是出于对性能原因的考虑,没有去实现它。而不是不能实现。

对于对象而言,每一次的数据变更都会对对象的属性进行一次枚举,一般对象本身的属性数量有限,所以对于遍历枚举等方式产生的性能损耗可以忽略不计,但是对于数组而言呢?数组包含的元素量是可能达到成千上万,假设对于每一次数组元素的更新都触发了枚举/遍历,其带来的性能损耗将与获得的用户体验不成正比,故vue无法检测数组的变动。

不过Vue3.0用proxy代替了defineProperty之后就解决了这个问题。


解决方案
数组
  1. ​ this.$set(array, index, data)

    //这是个深度的修改,某些情况下可能导致你不希望的结果,因此最好还是慎用
    this.dataArr = this.originArr
    this.$set(this.dataArr, 0, {data: '修改第一个元素'})
    console.log(this.dataArr)        
    console.log(this.originArr)  //同样的 源数组也会被修改 在某些情况下会导致你不希望的结果 
    
  2. splice

    //因为splice会被监听有响应式,而splice又可以做到增删改。
    
  3. 利用临时变量进行中转

    let tempArr = [...this.targetArr]
    tempArr[0] = {data: 'test'}
    this.targetArr = tempArr
    
对象
  1. this.$set(obj, key ,value) - 可实现增、改

  2. watch时添加deep:true深度监听,只能监听到属性值的变化,新增、删除属性无法监听

    this.$watch('blog', this.getCatalog, {
        deep: true
        // immediate: true // 是否第一次触发
      });
    
  3. watch时直接监听某个key

    watch: {
      'obj.name'(curVal, oldVal) {
        // TODO
      }
    }
    

🔥最后:大家有什么不同的见解,欢迎留言讨论。要是觉得不错,给小攻城狮点个赞呗👀

  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论
Vue的watch属性是用来监听数据变化并执行相应的操作。在Vue中,我们可以通过watch来深度监听数组变化。 使用深度监听数组的方法如下: ``` watch: { 'myArray': { handler: function(newVal, oldVal) { // 数组发生变化时的操作 }, deep: true } } ``` 其中,`myArray`是要监听数组名。通过设置`deep`为`true`,可以实现对数组内部元素的变化进行监听。当数组中的元素发生增加、删除、替换等操作时,handler函数会被触发。 例如,如果我们有一个数组`myArray`,当该数组中的元素发生变化时,我们可以在handler函数中执行相应的操作。比如,在数组中新增一个元素,可以在handler函数中打印出新增的元素: ``` watch: { 'myArray': { handler: function(newVal, oldVal) { console.log('新增元素:', newVal[newVal.length-1]); }, deep: true } } ``` 引用介绍了Vue的watch属性以及深度监听的方法,引用给出了一个示例,展示了当数组元素发生改变时的效果。通过设置watch的deep属性为true,可以实现对数组的深度监听。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [vue watch普通监听和深度监听实例详解(数组和对象)](https://download.csdn.net/download/weixin_38689041/12953951)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [VUE使用WATCH监听数组或对象的总结](https://blog.csdn.net/weixin_39645308/article/details/111783275)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [vue整合SSM项目实战](https://download.csdn.net/download/m0_55755339/88241603)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

°PJ想做前端攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值