Vue数据响应式原理简单解释

一.ObjectdefineProperty()

javascript有两种变化侦测的手段:Object.defineProperty()和ES6 的 Proxy;
vue2中使用的是Object.defineProperty(),vue3中使用的是Proxy。

Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

	//  把name放进data 打印出来
    const data = {};
    let name = "Vue";
    //value 和 get方法不能共存,拦截了对于属性的访问,这样就相当于把数据劫持了  //Cannot both specify accessors and a value or writable attribute
    Object.defineProperty(data,'name',{
      get:function (){
        console.log('get')
        return name;
      },
      set:function(newVal){
        console.log('set');
        name = newVal;
        //视图更新渲染
      }
    })
    console.log(data.name)
    data.name = '麦迪'
    console.log(data.name)

二.基本的响应式实现

vue源码中有一个核心方法叫 defineReactive() ,使用Object.defineProperty()f方法;主要用于将**非响应式数据转换为响应式数据,**什么意思呢,就是说将没有被侦测的数据,转化为变侦测的数据。这个过程,我比较喜欢叫它数据劫持。

// 简单的没有嵌套的数据
    const data = {
      name:"李小龙",
      age:33
    };
    //变成响应式数据
    observer(data)
    
    function observer(target){
      if(typeof target !== 'object' || target === null){
        return target;
      }
      // 循环数据的每一项
      for(let key in target){
        defineReactive(target,key,target[key]);
      }
    }
    function defineReactive(target,key,value){
      Object.defineProperty(target,key,{
        get:function(){
          return value;
        },
        set:function(newValue){
          value = newValue;
          console.log('更新视图')
        }
      })
    }
    data.name = '科比';
    data.age = 39;

三.复杂对象的响应式实现

Observer定义好以后,数据为复杂对象时,我们在defineReactive中进行深度监听,observer(value),observer中有判断,不是对象会返回。
defineReactive 和 observer相互嵌套

	const data = {
      name:"李小龙",
      age:33,
      friend:{
        friendName:"尤雨溪"
      }
    };
    //变成响应式数据
    observer(data)
    
    function observer(target){
      if(typeof target !== 'object' || target === null){
        return;
      }
      // 循环数据的每一项
      for(let key in target){
      // console.log(key,target[key])
        defineReactive(target,key,target[key]);
      }
    }

    function defineReactive(target,key,value){
      console.log(key,value)
      // 深度监听
      observer(value);  //defineReactive 和 observer相互嵌套
      Object.defineProperty(target,key,{
        get:function(){
          return value;
        },
        set:function(newValue){
          observer(newValue);  // 设置的时候也要监听
          value = newValue;
          console.log('更新视图')
        }
      })
    }
    // data.name = '科比';
    // data.age = 39;
    // data.friend.friendName = '刘龙斌';
    // data.age = {number: 99 };
    // data.age.number = 777;
    
    delete data.age;
    data.test = 'susu'
    // 删除或者增加data的属性,不会触发视图的更新;
    // vue2.0中Object.defineProperty没有办法处理属性删除和新增;
    // 需要使用另外的方法 删除使用Vue.delete 新增使用Vue.$set,会更新视图

vue2.0中删除或者增加data的属性,不会触发视图的更新;y因为 Object.defineProperty没有办法处理属性删除和新增;需要使用另外的方法 删除使用Vue.delete 新增使用Vue.$set,会更新视图

四.数组的响应式实现

const oldArrayProto = Array.prototype;
    const newArrProto = Object.create(oldArrayProto);
    console.log('oldArrayProto', oldArrayProto);
    // 要被改写的7个数组方法
    const methodsNeedChange = [
      'push',
      'pop',
      'shift',
      'unshift',
      'splice',
      'sort',
      'reverse'
    ];
    methodsNeedChange.forEach(methodName => {
      newArrProto[methodName] = function (){
        console.log('更新视图---222')
        oldArrayProto[methodName].call(this,...arguments)
      }
    }) // 这样改造下,push这些方法就可以触发更新视图,也可以执行原有的功能
    // console.log('newArrProto', newArrProto);

    //变成响应式数据
    observer(data)

    function observer(target) {
      if (typeof target !== 'object' || target === null) {
        return;
      }
      if(Array.isArray(target)){
        target.__proto__ = newArrProto;  //将数组之前的原型替换为新的原型
      }
      // 循环数据的每一项
      for (let key in target) {
        defineReactive(target, key, target[key]);
      }
    }

Array是通过定义自己的数组方法去覆盖数组原型方法的方式去侦测数据的。那前提肯定就是数组调用这些方法去改变自己的时候,我们才能侦测到。
所以:
当数组不同这些方法,而是通过其他方法去更改数组时,我们依然无法得知。比如
arr[1] = 3 这样去修改,并没有调用数组方法,我们就无法得知数据发生了变化。
或者arr.length = 0去清空了数组,我们同样也是无法得知的。

所以这个问题,还是要到vue3中通过proxy去解决了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值