vue2和vue3数据劫持代理和双向绑定实现原理

在vue2中,数据劫持代理和双向绑定都是通过Object.definePropertyAPI的setter和getter来实现,所以在此做同一记录

    **//vue2数据劫持代理**
    <script type="text/javascript">
      window.data = {
        name:'xs',
        age:'18'
      }
      let obs = new Observer(window.data)
      function Observer(res){
        let keys = Object.keys(res)
        keys.forEach((k)=>{
          Object.defineProperty(this,k,{
            get(){
              return res[k]
            },
            set(val){
              console.log('至此处监测data是否被改变,data改变时修改虚拟dom,刷新页面');
              console.log(window.data);
              res[k] = val
              console.log(window.data);
            }
          })
        })
      }
    </script>

代码如上,vue会先通Object.keys来拿到data中的属性列表,遍历这个属性列表拿到每个属性名,再通过Object.defineProperty在this上面绑定相同的属性名,并通过Object.defineProperty的get方法把this上属性名的值指向data导出的对象中同名的属性名的值,当this里面属性名的值改变时,会调用Object.defineProperty的set方法,把data导出对象里的同属性名的值改掉,这里有个注意点,改变的是data导出对象里的同属性名的值而不是this里面属性名的值

 **//vue2双向绑定实现原理**
 <input type="text" v-mode="msg" />
 <p v-mode="msg"></p>
 <script>
      const data = {
        msg: "你好",
      };
      const input = document.querySelector("input");
      const p = document.querySelector("p");
      input.value = data.msg;
      p.innerHTML = data.msg;
      //视图变数据跟着变
      input.addEventListener("input", function () {
        data.msg = input.value;
      });
      //数据变视图变
      let temp = data.msg;
      Object.defineProperty(data, "msg", {
        get() {
          return temp;
        },
        set(value) {
          temp = value;
          //视图修改
          input.value = temp;
          p.innerHTML = temp;
        },
      });
      data.msg = "小李";
    </script>


vue2双向绑定主要就是使用到了Objest.defineProperty的set方法,当双向绑定的值发生赋值的时候调用set方法,修改双向绑定的值及修改视图

在vue3中不在使用Object.definePropertyAPI来实现数据劫持代理和双向绑定都,而是使用es6新增的proxyAPI来实现(proxyAPI除了IE浏览器其他浏览器都支持,当然,现在也没必要去考虑IE浏览器),原因是Object.definePropertyAPI监听不到引用数据类型内部的属性增加和删除,这也导致vue2中不得不提供额外的API比如$set

Proxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义

//vue3双向绑定和数据劫持代理实现基本原理
<script type="text/javascript">    
    //定义需要代理的对象
      const data = {
        name:'张三',
        age:'18',
      }
    //定义代理执行函数
     const hander = {
        // target需要代理的对象,prop代理对象的属性名
        get(target,prop){
          console.log('get');
          // return Reflect.get(...arguments)
          return target[prop]
        },
        set(target,prop,value){
          console.log('set');
          target[prop] = value
        }
      }
     //封装的代理对象的函数
      function reactive(obj) {
        return new Proxy(obj, hander)
      }
      //这里的p可以理解为vue实例中的this
      let p = reactive(data)
      console.log(p.name);
      console.log(data.name);
      p.name = '李四'
      console.log(p.name);
      console.log(data.name);

打印结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值