响应式数据

一,概述

响应式,个人理解就是数据a变更,会自动更新所有用到a的地方。即它变更后会自动更新所有依赖于它的地方

具体在vue的代码中有这么几个地方。

1,html中渲染展示绑定的数据
2,watch和conputed中的依赖项

那如何实现自动更新?

首先需要能捕获它的变更,这样才可以在它变更的时候,去更新和它相关的地方。

现有的捕获数据变更的方式有以下三种:

1,利用Object.definePropery数据劫持。
2,利用Proxy数据代理。
3,利用对象的 get 和 set 函数

二,非响应式数据

最开始的时候,我们的代码时按照顺序执行的。

let single = 1;
let double = single * 2;
console.log(double);
single = 2;
console.log(double);//这时候double还是2

可以看到,代码按照顺序执行,single发生变化后,并不会更新依赖于它的double,所以这个single就不是一个响应式的数据。

三,基于Object.defineProperty实现

vue2的数据响应就是利用它实现的。

const handleClick = function () {
  obj.single++;
  console.log(obj.single, double);
};
const handleDouble = val => val * 2;
let obj = {};
let single = 2;
let double = handleDouble(single);
Object.defineProperty(obj, 'single', {
  get() {
    return single;
  },
  set(val) {
    single = val;
    docble = handleDouble(val); //依赖于它的值需要更新一次
  }
});

这里用obj这个对象,使用Object.defineProperty拦截了对其属性single的访问和修改,而修改时,我们就能在set函数中捕获对它的修改,从而去执行跟新相关数据的方法。(这里只有double依赖于它变化,所以执行更新double的方法。)

使用这个方法有一些缺点:

1,只有监听的属性才能被劫持。在vue2中体现出来就是一开始数据就要写在data中,要监听新增的属性需要用额外的api:this.$set。
2,删除属性时,不会被监听到。比如删除 obj.single 属性,set 函数就不会执行,double 还是之前的数值。体现在Vue 2 中,我们需要 $delete 一个专门的函数去删除数据。

四,基于Proxy实现

Proxy 是针对对象来监听,而不是针对某个具体属性,所以不仅可以代理那些定义时不存在的属性,还可以代理更丰富的数据结构,比如 Map、Set 等,并且我们也能通过 deleteProperty 实现对删除操作的代理。

vue3中的reactive就是采用的这种方式。

let handleDouble = n => n * 2;
let obj = {
  single: 1
};
let double = handleDouble(obj.single);
let proxy = new Proxy(obj, {
  get: function (target, prop) {
    return target[prop];
  },
  set: function (target, prop, value) {
    target[prop] = value;
    if (prop === 'single') {
      double = handleDouble(value);
    }
    return true;
  }
});
const handleClick = function () {
  proxy.single++;
  console.log(proxy.single, double);
};

这里使用proxy来代理obj这个对象,当我们修改proxy.single的时候,会被set函数捕获,从而修改obj.single的值。

值得注意的是,peoxy捕获的是该对象内 所有的变更。所以需要根据prop来判断变更的是哪个属性,然后针对这个属性完成它相关项的更新(handleDouble(value))。

五,基于对象的 get 和 set 函数

这种响应式的实现方式,只能拦截某一个属性的修改。vue3中的ref就是采用的这种方式。

let handleDouble = n => n * 2;
let ref = function (val) {
  let single = val;
  return {
    get value() {
      return single;
    },
    set value(val) {
      single = val;
      double = handleDouble(val);
    }
  };
};
let singleTest = ref(1);
let double = handleDouble(singleTest.value);
const handleClick = function () {
  singleTest.value++;
  console.log(singleTest.value, double);
};

当修改singleTest的值的时候,set函数会捕获这种改变,从而更新double的值。

这就是在vue3中为啥访问ref声明的参数时,需要加.value的原因。

六,总结

实际上,所谓的响应式数据,就是做到了以下两个事情。

1,能够捕获该数据的变更。
2,该数据变更后能自动调用更新依赖于它的相关页面/数据
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值