• vue源码:1、手写vue2.0之data添加观察


    本文是要实现对象使用Object.defineProperty重写对象,例

    //例把下面对象obj
    let obj={a:1};
    //修改成以下写法
    let aValue=1;
    Object.defineProperty(obj,a,{
      get(){
        return aValue;
      },
      set(newValue){
        if(aValue===newValue) return;
        aValue=newValue;
      }
    })
    这样在对对象属性进行获取、修改时,都能在get、set中监测到对象属性变化,但不能对对象属性值为数组进行监测,需要重写数组方法,下一篇

    首先介绍Object.defineProperty:

      作用是给对象的属性设置get、set、value、writable(可重写)、configurable(可配置、删除)、enumerable(可遍历)等

      其中writable不能和get、set一起出现,get、set不能和value一块出现

    Object.defineProperty(obj,key,{
      value,//属性值
      writable,//boolean
      configurable,//boolean
      enumerable,//boolean
      get(){},//不能和writable、value一块配置
      set(newValue){}//不能和writable、value一块配置
    })

    ******************************正文开始********************************

    在使用vue时

    //在这里只对vue的data进行处理
    let vm = new Vue({
      data:function(){
        return {
          a:1,
          b:{c:2}
        }
      }
    })
    可以把以上改成
    let options=
    {
    data:function(){
      return {
          a:1,
          b:{c:2}
        }
      }
    }
    let vm = new Vue(options)
    
    

    模仿以上,创建一个函数命名为Vue,

    function Vue(options){
    }

    问题:Vue如何将options里的data转成Object.defineProperty的写法

      解剖问题:

        1、在new  Vue()时即完成了到Object.defineProperty的转换

        解决:在new Vue()时执行了一个方法,命名为_init

    function Vue(options){
      this._init(options);
    }
    Vue.prototype._init=function(options){
      console.log("new的时候执行了_init")
    }
    解析 new Vue()会将所有的属性实例化,所以this_init()也会被执行,执行的时候会在对象的原型链中查找同名方法,所以会找到Vue.prototype._init方法,我们可以在_init中对options进行处理

    开始正题

    1、封装Object.defineProperty

    function defineReactive(obj,key,value){
      Object.defineProperty(obj,key,{
        get(){
          return value;
        },
        set(newValue){
          if(newValue===value) return;
          value=newValue;
        },
        configurable:true,
        enumerable:true
      })
    }

    2、封装判读当前变量是不是需要被观察

    function observe(data){
      if(typeof data!=="object"||data===null){return}
      walk(data);
    }

    3、遍历对象并设置Object.defineProperty

    function walk(data){
      let keys=Object.keys(data);
      for(let i=0;i<keys.length;i++){
        defineReactive(data,keys[i],data[keys[i]])
      }
    }

    以上会有一个问题,如果是{a:1}这种则没问题,如果{a:1,b:{c:2}},则不能遍历到底层,所以需要在设置get前对设置的值进行判断当前值需不需要被观察,如果需要被观察,先观察,不需要直接给当前属性赋值

    function defineReactive(obj,key,value){
      observe(value);//判断当前值需不需要被观察,需要观察,先观察再进行下面的处理
      Object.defineProperty(obj,key,{
        get(){
          return value;
        },
        set(newValue){
          if(newValue===value) return;
          value=newValue;
        },
        configurable:true,
        enumerable:true
      })
    }

    到此还有一个问题,就是给对象的某一个属性设置对象时,应当对设置的值进行观察,看是不是需要把值设计成 Object.defineProperty

    function defineReactive(obj,key,value){
      observe(value);//判断当前值需不需要被观察,需要观察,先观察再进行下面的处理
      Object.defineProperty(obj,key,{
        get(){
          return value;
        },
        set(newValue){
          if(newValue===value) return;
          value=newValue;
          observe(newValue);
        },
        configurable:true,
        enumerable:true
      })
    }

    至此初步设计完成,当然还有一个问题,就是对数组处理会有问题

    obj ={
      a:[2,3]
    }
    obj.a.push(4);
    //并不能监测数组属性的改变,需要重写数组方法,下一章介绍

    还需要解决一个问题,现在访问上面的数据是根据vm._data.key这样去访问,但是在使用vue时,是通过vm.key去访问数据的

    //因为我们给data里每一层属性都添加了Object.defineProperty 
    data(){
      return{
        a:1,
        b:{
          c:2
        }
      }
    }
    //ac三个均设置了Object.defineProperty,在访问属性c的时候,会首先触发b接着才会访问c,所以只需要在最外层设置代理即可
    //实现访问vm.a等同于访问vm._data.a
    proxy(vm,source,key){
      Object.defineProperty(vm,key,{
        get(){
          return vm[source][key]
        },
        set(newValue){
          vm[source][key]=newValue
        }
      })
    }
    
    
    修改initData函数
    function initData(vm){
      let data=vm.$options.data;
      data=vm._data=typeof data==="function"?data.call(vm):data||{};
      for(let key in data){
        proxy(vm,"_data",key);
      }
      observe(data);
    }
  • 相关阅读:
    第5次作业
    第六次作业
    第五次作业
    软件需求最佳实践阅读笔记05
    软件需求最佳实践阅读笔记04
    构建民航知识图谱
    软件需求最佳实践阅读笔记03
    软件需求最佳实践阅读笔记02
    软件需求最佳实践阅读笔记01
    程序员的自我修养阅读笔记03
  • 原文地址:https://www.cnblogs.com/shui1993/p/15410858.html
Copyright © 2020-2023  润新知