最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue响应式原理剖析

    正文概述 掘金(jackjieli)   2021-02-02   842

    响应式原理是Vue的核心思想,vue2.x使用的是Object.defineProperty(),3.x使用了Proxy代理。本文主要描述了defineProperty和Proxy的使用原理和特点。

    defineProperty

    名词解释

    define: 定义
    property: 属性
    defineProperty: 定义属性的方法

    用法

    Object.defineProperty(obj, prop, description)

    function defineProperty(){
      const _obj = {};
      Object.defineProperty(_obj, 'a', {
        value: 22
      })
    
      return _obj;
    
    }
    
    const obj = defineProperty()
    console.log(obj);
    
    

    Vue响应式原理剖析

    function defineProperty2(){
      const _obj = {};
      Object.defineProperties(_obj, {
        a:{
          value: 22222
        },
        b:{
          value: 666
        }
      })
    
      return _obj;
    
    }
    
    const obj = defineProperty2()
    

    Vue响应式原理剖析

    直接使用value定义的属性,不可修改 不可枚举 不可删除

    function defineProperty2(){
      const _obj = {};
      Object.defineProperties(_obj, {
        a:{
          value: 1
        },
        b:{
          value:2
        }
      })
    
      return _obj;
    
    }
    
    const obj = defineProperty2()
    
    obj.a = 555;
    console.log(obj);  //不可修改
    
    
    for(var k in obj){
      console.log(obj[k]);   //不可枚举
    }
    
    delete obj.a;   //不可删除
    console.log(obj);
    

    defineProperty的配置项

    function defineProperty2(){
      const _obj = {};
      Object.defineProperties(_obj, {
        a:{
          value: 1,
          writable: true, //默认为false
          enumerable: true, //默认false
          configurable: true //默认false  是否可删除
        },
        b:{
          value:2
        }
      })
      return _obj;
    }
    
    const obj = defineProperty2()
    
    obj.a = 555;
    console.log('修改后', obj);  //不可修改
    
    
    for(var k in obj){
      console.log('枚举', obj[k]);   //不可枚举
    }
    
    delete obj.a;   //不可删除
    console.log('删除后', obj);
    

    Vue响应式原理剖析

    defineProperty的set和get

    function defineProperty(){
      const _obj = {};
    
      var a =1;
    
      Object.defineProperties(_obj, {
        a:{
          get(){
            console.log('get', a);
            
            return a;
          },
          set(newVal){
            
            a = newVal;
            console.log('set', a);
          }
        }
      })
    
      return _obj;
    }
    
    
    const ee = defineProperty()
    

    注意:set get不能和valve writable一起用,一般都像上面这样,将值从外面复用进来,里面只写set get ! Vue响应式原理剖析

    使用案例一:利用property实现一个对对象赋值,就可以添加到数组中的方法

    function dataArray(){
      var _val = null,
          _arr = [];
      Object.defineProperty(this, 'val', {
        get(){
          return _val;
        },
    
        set(newVal){
          _val = newVal;
          _arr.push({'val': _val})
        }
      });
    
      this.getArr = ()=>{
        return _arr;
      }
    }
    
    
    var arr = new dataArray();
    arr.val =1111;
    arr.val =22222;
    console.log(arr.getArr());
    

    Vue响应式原理剖析

    defineProperty的特点

    1.defineProperty 是js比较底层的能力 官方应该是不太建议去使用的,之所以有它是为了弥补js在枚举,可写等的缺陷 对属性的控制不够彻底;
    2.proxy是大的方向
    3.defineProperty还有一个类似于bug的特点 就是:set get不能和valve writable一起用

    案例二:demo-用defineProperty实现一个计算器

    github.com/lijieJack/C…

    defineProperty 数据劫持 给对象扩展属性 属性进行设置

    proxy

    proxy对对象、数组、方法的代理

    // let obj = new Proxy(target, handler)
    
    // target 目标对象   要处理的对象
    // handler 容器  无数可以处理对象属性的方法
    
    
    // 作用: 自定义对象属性的获取 赋值  枚举  函数调用等功能
    
    const target = {
      a:1,
      b: 2
    }
    
    let proxy = new Proxy(target, {
      get(target, prop){
       console.log('this property:' + target[prop]);
       return target[prop];
      },
    
      set(target, prop, value){
        target[prop] = value;
        console.log('set ', target[prop]);
      }
    })
    
    console.log(target.a);
    console.log(proxy.a);
    
    
    proxy.b =3
    
    
    
    // proxy可以代理 对象   数组   方法
    
    // 代理数组
    const arr = [
      {name: 'sss', age:18},
      {name: 'sss', age:18},
      {name: 'sss', age:18},
      {name: 'sss', age:18}
    ]
    
    const arrProxy = new Proxy(arr, {
      get(arr, prop){
        console.log('prop:',prop);
        
        return arr[prop];
      },
    
      set(arr, prop, value){
        arr[prop] = value;
      }
    })
    
    console.log('arrProxy[1]', arrProxy[5]);
    arrProxy[2] = {bb:111}
    console.log('arrProxy', arrProxy, 'arr', arr);
    
    
    //代理方法
    function func (){
      console.log(111);
      
    }
    func.a = 888;
    
    const funcProxy = new Proxy(func,{
      get(func, prop){
        return func[prop]
      },
      set(func, prop, value){
        func[prop] = value
      }
    })
    
    console.log(funcProxy.a);
    funcProxy.a = 7777
    console.log(funcProxy.a);
    console.log('func', func, 'funcProxy', funcProxy);
    
    

    Vue响应式原理剖析

    Proxy实现的剖析

    Proxy是浏览器基本的api实现,已有很好的兼容性。目前主要IE不支持,我们使用Object.defineProiperty() 来实现一个Proxy

    //手动实现一个Proxy
    // Proxy 是浏览器自带的api功能  当浏览器不支持时 如IE, 可以自己手动构建实现一个
    
    function myProxy(target, handle) {
      const _target = deepClone(target);
    
      Object.keys(_target).forEach((key)=>{
        console.log('key', key);
        
        Object.defineProperty(_target, key, {
    
          get(){
            console.log('defineProperty get:', key);
            return handle.get && handle.get(target, key);
          },
          set(newVal){
            handle.set && handle.set(target, key, newVal);
          }
        })
    
      })
      return _target;
    
    
      // 深拷贝
      function deepClone(org, tar){
        tar = tar || {};
        for(let key in org){
    
          if(org.hasOwnProperty(key)){
            if( typeof org[key] === 'object' && org[key]!==null ){
              if(Object.prototype.toString.call(org[key]) === '[object Array]'){
                //是数组
                tar[key] = [];
              }else{
                tar[key] = {};
              }
              deepClone(org[key], tar[key])
            }else{
              tar[key] = org[key]
            }
          }
    
        }
    
        return tar;
      }
    }
    
    
    
    const target = {
      a: {
        s:333
      },
      b: 2
    }
    
    const proxyTarget = new myProxy(target, {
      
      
      get(target, prop){
        console.log('proxy target:',target, prop);
        console.log(222222222);
        
        return target[prop]
      },
      set(target, prop, value){
        target[prop] = value;
      }
    })
    

    Vue响应式原理剖析

    Proxy其他可操作的方法

    除了get set 还有其他如:has,deleteProperty等共十四种操作对象的方法。 Vue响应式原理剖析

    defineProperty 与 Proxy的对比:

    defineProperty原则上是给对象添加属性时使用的,在修改数组的长度,用索引去设置元素的值的时候 ,数组的push pop时 是无法触发defineProperty的set方法的。vue2.0对数组的操作是vue自己重新写的,而不是原生写的,这样导致vue2.0的代码很重。
    Proxy 没有这个问题,功能更加强大。
    defineProperty是拦截
    Proxy是代理

    为什么在vue2.0没有使用proxy?

    Proxy是ES6的语法 是一个构造函数,当时考虑到兼容性 在2.x版本就没用Proxy 3.0时 es6的支持更好,Vue在代码的编译过程中做了代码的转换,proxy转化为DefineProperty,解决兼容问题。Proxy自身支持IE9以上。

    在2.x中data:

    data(){
        return {
            
        }
    }
    

    设计为函数返回值的形式是为了: 1.防止引用的时候被篡改
    2.直接返回一个对象 这个对象直接用来做defineProperty处理

    3.x中

    data:{
        
    }
    

    是用来被代理操作的 不直接操作它,故不用函数返回值的形式。

    使用Reflect

    使用Reflect实现 函数式的方法操作 而不是,声明式的操作,会更方便维护和使用。 Vue响应式原理剖析

    Reflect的好处:

    1.js受原来一切都是对象影响,很多方法挂在Object(object.prototype.constract)上设计不完善.很多方法将移到Reflect。
    2.Reflect有函数操作的返回值,true false更方便操作
    3.兼容性:es6
    4.handle中的方法都可以用Reflect实现。
    5.全局可用。

    下面是Reflect下面的方法: Vue响应式原理剖析

    总结

    本文分别描述了Vue双向绑定的核心:Object.defineProperty()和Proxy的用法,如何手动自己去实现一个Proxy,对两者进行了对比,最好描述了使用Reflect的一些好处。

    如果对你有帮助 欢迎交流~


    起源地下载网 » Vue响应式原理剖析

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元