Vue响应式

  • 组件data的数据一旦变化,立刻触发视图的更新
  • 数据驱动视图的第一步

核心API-Object.defineProperty

1.1回顾Object.defineProperty

Object.defineProperty(obj, prop, descriptor)

  obj:要定义属性的对象。

  prop:要定义或修改的属性的名称或 Symbol 。

  descriptor:要定义或修改的属性描述符。

参考:Object.defineProperty() - JavaScript | MDN


        // 下面代码表示给对象obj1添加一个age属性
        let age = 10;
        Object.defineProperty(obj1,'age',{
            get(){
                console.log('get');
                return age;
            },
            set(newVal){
                console.log('set');
                age = newVal
            }
        })
        obj1.age = 20;
        console.log(obj1.age);

 1.2通过Object.defineProperty实现响应式

         首先这里是用到了数据代理模式,将Vue配置对象中的data配置项中的数据,通过Object.defineProperty挂载到了vue身上,随后我们访问的数据就都是从Vue实例对象上获得的。具体实现看下面的代码:

基本代码

        // 监测者函数,负责接受一个数据,并其进行监测
        function Observer(data){
            // 只监听对象和数组的属性
            if(typeof data !== 'object' || data===null) return data;

            // 如果data合法,就把他身上的所有属性都通过defineProperty重新定义,并且设置setter和getter方法
            // for in 可遍历对象和数组
            for(let key in data){
                // 封装一个函数
                defineReactive(data,key,data[key])
            }
        }

        
        function defineReactive(data,key,val){
            // 核心API
            Object.defineProperty(data,key,{
                get(){
                    return val;
                },
                set(newValue){
                    val = newValue;
                    console.log('视图更新');
                }
            })

        }
        

深度监听

上述代码解决不了深度监听的问题,为了实现深度监听,需要修改一下代码

        //调用核心API进行数据代理

        function defineReactive(data,key,val){
            //这里再调用一次Observer函数实现深度监听,
            //也就是如果发现你传过来的val还是一个引用类型,那么继续向下监听,
            //如果不是,Observer函数会自动返回
            Observer(val)
            // 核心API
            Object.defineProperty(data,key,{
                get(){
                    return val;
                },
                set(newValue){
                    val = newValue;
                    console.log('视图更新');
                }
            })

        }

监听数组     

  但是目前这个代码还存在问题,那就是此时无法监听到数组的变化。为了监测到数组的变化,需要进一步修改代码

        // 记录Array.prototype
        let oldArrayPrototype = Array.prototype;
        // Object.create()方法创建一个新对象,接受的参数是该对象的原型
        let newArrayPrototype = Object.create(oldArrayPrototype);
        // 把常用的方法都重写一遍
        ['push','pop','splice','shift','unshift'].forEach((func)=>{
            newArrayPrototype[func] = function(){
                console.log('视图更新');
                oldArrayPrototype[func].call(this,...arguments)
            } 
        })

        // 监测者函数,负责接受一个数据,并其进行监测
        function Observer(data){
            // 只监听对象和数组的属性
            if(typeof data !== 'object' || data===null) return data;
            // 如果是数组,那么就修改其原型
            if(Array.isArray(data)) data.__proto__ = newArrayPrototype;

            // 如果data合法,就把他身上的所有属性都通过defineProperty重新定义,并且设置setter和getter方法
            // for in 可遍历对象和数组
            for(let key in data){
                // 封装一个函数
                defineReactive(data,key,data[key])
            }
        }

几个缺点

  1. 为了实现深度监听,如果数据对象比较复杂,那么监听创建的成本就比较高
  2. 对于数组需要进行额外的操作实现监听
  3. 新增属性和删除属性是监听不到的,需要通过vue.set、vue.delete
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值