数据 vue 监控_vue2.0 双向数据绑定的局限性和简单实现

本文探讨了Vue2.0中双向数据绑定存在的两个问题:未声明属性的默认追加数据不更新视图,以及无法通过数组长度或索引直接修改。这些问题源于Object.defineProperty不支持数组操作,Vue通过重写数组方法实现数据劫持。文章通过简单的代码示例进行了说明。
摘要由CSDN通过智能技术生成

f20e43fd598871aee9ff1cc065fd4a54.png

vue2.0 双向数据绑定的局限性

我们知道,vue2.0内部是通过 Object.defineProperty 来进行数据劫持等操作的,但也正因为这样,所以会存在一些局限性:

1.如果属性不存在,默认后增加的数据不会更新到视图

我们可以看以下代码:

<div id="app">
        {{info.name}} {{info.age}}
</div>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                msg: 'emmmmmmm',
                info:{
                    name:'cy'
                }
            }
        })
       vm.info.age=18
   </script>

这段代码的运行结果是cy,并没有出现cy 18,这也说明了,如果对没有在data钩子声明了的属性赋值,不会同步更新到视图上面去。

2.数组不能通过长度修改,也不能通过数组的索引修改

我们可以看以下代码:

<div id="app">
        {{arr}}
</div>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                msg: 'emmmmmmm',
                arr: [1, 2, 3]
            }
        })
        vm.arr.length--
   </script>

这段代码的运行结果是[1,2,3],并没有出现我们预期的[1,2],这也说明了数组是不能通过长度进行修改,并且更新到视图。同理,也不能通过数组的索引进行修改,这里就不演示了。

双向数据绑定的局限性原因

那么,造成这种局限性的原因是什么呢,下面我们通过一个模仿vue源码内部实现的简单demo来研究下:

//数据劫持的实现
function observer(obj) {
    if (typeof obj == 'object') {
        for (let key in obj) {
            defineReactive(obj, key, obj[key])
        }
    }
}
function defineReactive(obj, key, value) {
    observer(value)//判断value是不是一个对象 如果是对象 就递归 实现深度监控
    Object.defineProperty(obj, key, {
        get() {
            return value
        },
        set(newVal) {
            observer(newVal)//如果重新给数据绑定一个新的对象  也要监控到新对象的属性
            console.log('数据更新了 劫持到了')
            value = newVal
        }
    })
}

通过代码我们可以看到,vue内部实质上是对data挂载的对象进行了一次深度遍历,然后给每个属性都通过 Object.defineProperty() 进行改造,最后实现数据劫持等操作。

这就可以很好的解释我们的第一种局限性:如果我们给data钩子里面不存在的属性进行赋值的时候,实质上没有通过defineReactive()方法对这个新增的属性进行改造,让他拥有数据劫持等的能力,所以它不会更新到视图层。

Object.defineProperty不能对数组进行操作

到这里,很多小伙伴会疑惑,Object.defineProperty不能对数组进行操作,那么vue内部是如果对数组进行数据劫持的呢。其实很简单,vue内部通过重写所有数组的方法来进行数据劫持,这是我实现的一个类似的小demo:

//vue里面把所有的数组方法都重写了
let arr=['push','slice','shift']
arr.forEach(method=>{
    let oldMethod=Array.prototype[method]
    Array.prototype[method]=function(value){
        console.log('通过改写数组的api实现数组的数据劫持')
        oldMethod.call(this,value)
    }
})

既然我们了解了vue内部对数组的相关操作,我们也可以很好的理解为什么会出现第二种局限性了:因为vue内部只是对数组的所有方法进行重写数据劫持,但是对数组的长度和索引的变化没有进行相应的操作,所以才会出现这种局限性。

这个也是之前开发时候遇到的一些小坑,不过后来也通过一些如$set等来解决了
这是我第一次写文章,虽然涉及的比较简单,但是文笔和表述还是不太清楚,大家见谅一哈。后续会写一下我对vuex、vue-router、vue-cli、ssr、pwa、jwt、vue测试、权限控制等的源码实现或使用的见解,如果感兴趣的小伙伴可以关注下哦。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值