vue源码深入研究

219 阅读3分钟

一: vue 源码解析之响应原理 Obj.defineProperty

参数:

 enumerable, //是否枚举 就是可遍历的意思
 writable:true, // 是否可写
 configurable:true // 是否被删除
 get 
 set

案例1 对象响应

      -----------defineReactive 函数 -----------
      
          function defineReactive(data,key,val){
            console.log("我是defineReactive",data,key)
            if(arguments.length==2){
              val=data[key];
            }
            let childOb=observe(val)
            Object.defineProperty(data,key,{
              get:function(){ // 不用和value值同时使用
                console.log('我访问了name属性')
                return val
              },
              set:function(newValue){
                console.log('视图改变值为',newValue)
                if(newValue === val){
                  return;
                }
                val=newValue;
                childOb=observe(newValue)
              }

            })
          }
          
          
 -----------def 函数 -----------
 
 
      function def(obj,key,value,enumerable){
        Object.defineProperty(obj,key,{
          value,
          enumerable, //是否枚举 就是可遍历的意思
          writable:true, // 是否可写
          configurable:true // 是否被删除
        })
      }
      
      

------- Observer作用:将一个正常的Object转换每个层级的属性都是响应式(可祯听的)object-----
      class Observer {
        constructor (val) {
          console.log('我是构造器Observer',val)
          def(val,'__ob__',this,false)
          this.walk(val)
        }
        //遍历
        walk(val){
          for(let k in val){
            defineReactive(val,k)
          }
        }
      }

-----------observe函数----------------------------
      function observe(value){
        if(typeof value !='object') return;
        var ob;
        if(typeof value.__ob__!=='undefined'){
          ob=value.__ob__;
        }else{
          ob= new Observer(value)
        }
        return ob;
      }
      
      
  ----------------- 调用------------------------
  
        let obj={
        a:{
          a1:{
            a2:{
              a3:10
            }
          }
        },
        b:{
          b1:6
        },
        c:{
          c1:7
        },
      };
 
      observe(obj)
  

案例2 在前面基础添加数组的响应

array.js文件

const arrayPrototype = Array.prototype;
export const arrayMethods = Object.create(arrayPrototype)
const methodsNeedChange = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'sort',
    'reverse'
]
methodsNeedChange.forEach(methodName => {
    //备份原来的 因为 push
    const orginal = arrayPrototype[methodName]
        // 定义新方法
    def(arrayMethods, methodName, function() {

        const result = orginal.apply(this, arguments)
        let arg2 = [...arguments] // 转数组
            // 把这个数组身上的__ob__取出来,__ob__已被添加了,为什么已经被添加了? 因为数组肯定不是最高层,比如obj.g属性是数组,
            //obj不能是数组,第一次遍历obj这个对象的第一层时候,已经给g属性(就是这个数组)添加了__ob__属性
        const ob = this.__ob__;
        // 有三种方法 push 、unshift、splice能够插入新项,现在把新项也变成observe
        let inserted = [];
        switch (methodName) {
            case 'push':
            case 'unshift':
                inserted = arg2;
            case 'splice':
                // splice格式splice(下标,数量,插入新项)
                inserted = arg2.slice(2);
                break;
        }
        // 判断有没有要出入新项,让新项也变成响应
        if (inserted) {
            ob.observeArray(inserted)
        }

        console.log('拉拉')
        return result;

    }, false)

})

function def(obj, key, value, enumerable) {

    Object.defineProperty(obj, key, {
        value,
        enumerable, //是否枚举 就是可遍历的意思
        writable: true, // 是否可写
        configurable: true // 是否被删除
    })
}

调用文件

   definePropretyFun(){


      function defineReactive(data,key,val){
        console.log("我是defineReactive",data,key)
        if(arguments.length==2){
          val=data[key];
        }
        let childOb=observe(val)
        Object.defineProperty(data,key,{
          get:function(){ // 不用和value值同时使用
            console.log('我访问了name属性')
            return val
          },
          set:function(newValue){
            console.log('视图改变值为',newValue)
            if(newValue === val){
              return;
            }
            val=newValue;
            childOb=observe(newValue)
          }
          
        })
      }

      function def(obj,key,value,enumerable){
        console.log(obj,key,value,enumerable)
        Object.defineProperty(obj,key,{
          value,
          enumerable, //是否枚举 就是可遍历的意思
          writable:true, // 是否可写
          configurable:true // 是否被删除
        })
      }

      // Observer作用:将一个正常的Object转换每个层级的属性都是响应式(可祯听的)object
      class Observer {
        constructor (val) {
          console.log('我是构造器Observer',val)
          def(val,'__ob__',this,false)
          
          
          if(Array.isArray(val)){
            // 如果是数组,要强制将该数组的原型执行 arrayMethods
            Object.setPrototypeOf(val,arrayMethods)
            //让这个数组变的obsever
            this.observeArray(val);
          }else{
            this.walk(val)
          }

        }
        //遍历
        walk(val){
          for(let k in val){
            defineReactive(val,k)
          }
        }
        // 数组的特殊遍历
        observeArray(arr){
          for(let i=0,l=arr.length;i<l;i++){
            // 逐项进行observe
            observe(arr[i])
          }
        }
      }


      function observe(value){
        if(typeof value !='object') return;
        var ob;
        if(typeof value.__ob__!=='undefined'){
          ob=value.__ob__;
        }else{
          ob= new Observer(value)
        }
        return ob;
      }


      let obj={
        a:{
          a1:{
            a2:{
              a3:10
            }
          }
        },
        b:{
          b1:6
        },
        c:{
          c1:7
        },
        d:[1,2,3]
      };
 
     observe(obj)
     obj.d.push(4)
     obj.d.splice(2,1,88) // 把下标2 删除,改成 88
     obj.d.splice(1,1,[21,32])
     console.log(obj.d)

image.png

依赖收集

image.png

image.png