vue2 vs vue3 -- 响应式对象区别,vue2中通过Object.defineproperty、Vue3中ref(Object.defineproperty)reactive(proxy)

vue2 vs vue3 系列文章

可浏览博客主页的Vue专栏,会陆续添加相关文章,有问题或者可以优化的地方也希望大大门告知
共同进步 :)

在这里插入图片描述



vue2.x 的响应式

实现原理

  1. 对象类型:通过Object.defineProperty() 对属性的读取跟修改进行拦截(数据劫持)。
  2. 数组类型:通过重写更新数据的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
let obj={name:"Penk666"}
Object.defineProperty(obj,'name',{
	get(){},
	set(value)(){}
})

存在问题

  1. 新增属性、删除属性,界面不会更新。
  2. 直接通过下标修改数组,界面不会更新。

错误测试代码

此处的错误就是没有像对obj进行判断是否为对象就开始遍历~ 傻逼操作了,引以为戒...

/**
  * vue2 实现对象数据劫持
  */
var person = { name: 'Penk666', age: 32, job: { j1: { salary: 10000 } } };
function Observer(obj) {
  // 获取对象的键名
  let keys = Object.keys(obj);
  // 遍历
  for (let i of keys) {
    // 如果是对象,并且不是null(null也是对象),则继续监听,形成递归
    if (typeof obj[i] == 'object' && typeof obj[i] !== null) {
      Observer(obj[i]);
    }
    // 主方法,监听对象的属性。
    // 缺点:无法监听新增对象obj.xxx 或者删除对象 delete obj.a。
    Object.defineProperty(obj, i, {
      get() {
        console.log(`数据被获取了${obj[i]}...`);
        return obj[i];
      },
      set(newValue) {
        console.log(`数据变化了,obj.${i}:${newValue}...`);
        obj[i] = newValue;
      },
      enumerable: true,
      configurable: true
    });
  }
}

Observer(person);
console.log('person:', person);
console.log('name:', person.name);

如下图:
在这里插入图片描述
解决方案:先判断obj是否为对象,再进行遍历。由于vue的data为obj,所以第一步就可以进行判断了~
约定俗成的东西记住即可~~~

测试代码

这边使用es6中的class,使用面向对象编程的写法。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      /**
       * vue2 实现对象数据劫持
       */
      var person = { name: 'Penk666', age: 32, job: {  salary: 10000 }  };
      // 数据劫持
      class Observer {
        constructor(data) {
          //初始化时候劫持数据
          this.observer(data);
        }
        observer(data) {
          if (data && typeof data == 'object') {
            for (let key in data) {
              // 这里传入data[key] 是为了形成闭包,避免循环调用造成的内存泄漏
              this.defineReactive(data, key, data[key]);
            }
          }
        }
        defineReactive(obj, key, val) {
          this.observer(val);
          Object.defineProperty(obj, key, {
            enumerable: true,
            get() {
              console.log(`Object.defineProperty监听到数据被获取了,当前值${val}...`);
              return val;
            },
            set: (newVal) => {
              if (val == newVal) return;
              console.log(`Object.defineProperty监听到数据修改了,当前值${newVal}...`);
              val = newVal;
              // 重新赋值的时候劫持数据
              this.observer(newVal);
            }
          });
        }
      }

      new Observer(person);
    </script>
  </body>
</html>


测试用例

温馨提示:不要使用++ 操作…

// get 获取属性值
person.name;
console.log('@@');
// set 设置属性值
person.name += '!';
console.log('@@');
// 深层次对象 set
person.job.salary=22;
console.log('@@');

效果如下图:
在这里插入图片描述


vue3.x 的响应式

优点:可以监听到对象的新增,以及删除操作;不需要递归实现。

实现原理

  1. 通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读取、属性的添加、属性的删除等。
  2. 通过Reflect(反射):对被代理对象的属性进行操作。虽然可以直接在obj上操作,但是JS已经开始将Object对象的方法转移到Reflect上了,怕是为了解耦。

测试代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      /**
       * vue3 实现对象数据劫持
       */
      var o = { a: 1, b: 2, c: { d: 3 } };
      var arr = [1, 2, 3];
      function Observer(obj) {
        return (p = new Proxy(obj, {
          get(target, key) {
            console.log(`proxy对象监听到数据被获取了,当前值${target[key]}...`, target, key);
            return Reflect.get(target, key);
          },
          set(target, key, newValue) {
            console.log('proxy对象监听到数据新增或更新了...', target, key, newValue);
            Reflect.set(target, key, newValue);
          },
          deleteProperty(target, key) {
            console.log(`proxy对象监听到源对象删除${key}了...`);
            Reflect.deleteProperty(target, key);
          }
        }));
      }
      var proxy = Observer(o);
    </script>
  </body>
</html>

测试用例

// get一个属性
proxy.a;
// 删除一个属性
delete proxy.b;
// 新增一个属性
proxy.e = 6;
// 修改深层属性
proxy.c.cc.ccc = 33;

效果如下图:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Penk是个码农

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

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

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

打赏作者

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

抵扣说明:

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

余额充值