js css html

响应式原理

2022-10-08  本文已影响0人  未路过

1 什么是响应式

81.PNG

2 响应式函数设计

82.PNG 83.PNG
// 封装一个响应式的函数
let reactiveFns = []
function watchFn(fn) {
  reactiveFns.push(fn)
}

// 对象的响应式
const obj = {
  name: "why",
  age: 18
}

watchFn(function() {
  const newName = obj.name
  console.log("你好啊, 李银河")
  console.log("Hello World")
  console.log(obj.name) // 100行
})

watchFn(function() {
  console.log(obj.name, "demo function -------")
})

function bar() {
  console.log("普通的其他函数")
  console.log("这个函数不需要有任何响应式")
}

obj.name = "kobe"
reactiveFns.forEach(fn => {
  fn()
})



3 依赖收集类的封装

84.PNG
class Depend {
  constructor() {
    this.reactiveFns = []
  }

  addDepend(reactiveFn) {
    this.reactiveFns.push(reactiveFn)
  }

  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}

// 封装一个响应式的函数
const depend = new Depend()
function watchFn(fn) {
  depend.addDepend(fn)
}

// 对象的响应式
const obj = {
  name: "why", // depend对象
  age: 18 // depend对象
}

watchFn(function() {
  const newName = obj.name
  console.log("你好啊, 李银河")
  console.log("Hello World")
  console.log(obj.name) // 100行
})

watchFn(function() {
  console.log(obj.name, "demo function -------")
})

obj.name = "kobe"
depend.notify()

4 自动监听对象变化

那么我们接下来就可以通过之前学习的方式来监听对象的变量:

方式一:通过 Object.defineProperty的方式(vue2采用的方式);

方式二:通过new Proxy的方式(vue3采用的方式);

class Depend {
  constructor() {
    this.reactiveFns = []
  }

  addDepend(reactiveFn) {
    this.reactiveFns.push(reactiveFn)
  }

  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}

// 封装一个响应式的函数
const depend = new Depend()
function watchFn(fn) {
  depend.addDepend(fn)
}

// 对象的响应式
const obj = {
  name: "why", // depend对象
  age: 18 // depend对象
}

// 监听对象的属性变量: Proxy(vue3)/Object.defineProperty(vue2)
const objProxy = new Proxy(obj, {
  get: function(target, key, receiver) {
    return Reflect.get(target, key, receiver)
  },
  set: function(target, key, newValue, receiver) {
    Reflect.set(target, key, newValue, receiver)
    depend.notify()
  }
})

watchFn(function() {
  const newName = objProxy.name
  console.log("你好啊, 李银河")
  console.log("Hello World")
  console.log(objProxy.name) // 100行
})

watchFn(function() {
  console.log(objProxy.name, "demo function -------")
})

watchFn(function() {
  console.log(objProxy.age, "age 发生变化是需要执行的----1")
})

watchFn(function() {
  console.log(objProxy.age, "age 发生变化是需要执行的----2")
})

objProxy.name = "kobe"
objProxy.name = "james"
objProxy.name = "curry"

objProxy.age = 100

5 依赖收集的管理

85.PNG
  class Depend {
    constructor() {
      this.reactiveFns = []
    }

    addDepend(reactiveFn) {
      this.reactiveFns.push(reactiveFn)
    }

    notify() {
      this.reactiveFns.forEach(fn => {
        fn()
      })
    }
  }




  // 对象的响应式
  const obj1 = {
    name: "why", // depend对象
    age: 18 // depend对象
  };
  const obj2 = {
    name: "kobe", // depend对象
    age: 32 // depend对象
  };

  const weakMap = new WeakMap();
  const objtest = { name: 'key' }
  //  console.log(weakMap.set(objtest, 'aaa'))
  console.log(weakMap.get(objtest)) //undefined  没有的化返回的是undefined

  function setDepend(target, key) {
    let targetMap = weakMap.get(target);
    if (!targetMap) {
      targetMap = new Map();
      weakMap.set(target, targetMap);
    }
    let depend = targetMap.get(key);
    if (!depend) {
      depend = new Depend();
      targetMap.set(key, depend)
    }
    return depend
  }



 /*  const objProxy = new Proxy(obj1, {
    get: function (target, key, receiver) {
      return Reflect.get(target, key, receiver)
    },
    set: function (target, key, newVaule, receiver) {
      Reflect.set(target, key, newVaule, receiver);
      setDepend(target, key).notify();
    }
  }) */

  //forEach没有返回值,map有
  let [obj1Proxy, obj2Proxy] =  [obj1, obj2].map(item => {
  return  new Proxy(item, {
      get: function (target, key, receiver) {
        return Reflect.get(target, key, receiver)
      },
      set: function (target, key, newVaule, receiver) {
        Reflect.set(target, key, newVaule, receiver);
        setDepend(target, key).notify();
      }
    })
  });





  function obj1NameFn1() {
    console.log(obj1Proxy.name);
    console.log("obj1NameFn1被执行")
  }

  function obj1NameFn2() {
    console.log("obj1NameFn2被执行")
  }

  function obj1AgeFn1() {
    console.log("obj1AgeFn1被执行")
  }

  function obj1AgeFn2() {
    console.log("obj1AgeFn2被执行")
  }

  
function obj2NameFn1() {
  console.log("obj2NameFn1被执行")
}

function obj2NameFn2() {
  console.log("obj2NameFn2被执行")
}


function obj2AgeFn1() {
  console.log("obj2AgeFn1")
}

function obj2AgeFn2() {
  console.log("obj2AgeFn2")
}

/* WeakMap应用里面的方法
      const obj1PropertyMap = new Map()
      obj1PropertyMap.set('name', [obj1NameFn1, obj1NameFn2])
      obj1PropertyMap.set('age', [obj1AgeFn1, obj1AgeFn2])
      const obj2PropertyMap = new Map()
      obj2PropertyMap.set('name', [obj2NameFn1, obj2NameFn2])
      obj2PropertyMap.set('age', [obj2AgeFn1, obj2AgeFn2])

      const objWeakMap = new WeakMap()
      objWeakMap.set(obj1, obj1PropertyMap)
      objWeakMap.set(obj2, obj2PropertyMap)
      objWeakMap
            .get(obj1)
            .get('name')
            .forEach((fn) => fn()) */


  function watchFn(target, key, ...fns) {
    fns.forEach(item => {
      setDepend(target, key).addDepend(item);
    })
  }

  watchFn(obj1, "name", obj1NameFn1, obj1NameFn2);

  watchFn(obj1, "age", obj1AgeFn1, obj1AgeFn2 )

  watchFn(obj2, "name", obj2NameFn1, obj2NameFn2);

  watchFn(obj2, "age", obj2AgeFn1, obj2AgeFn2 )



  obj1Proxy.name = "coder";
  obj1Proxy.age = 118;
  obj2Proxy.name = "jiff";
  obj2Proxy.age = 89;

  console.log(obj2Proxy.age);

6 正确的收集依赖

113.PNG

上面时通过watchFn(obj1, "name", obj1NameFn1, obj1NameFn2);这个方法,手动的为obj1的name属性添加了方法obj1NameFn1和obj1NameFn2, 我们想着就是不手动添加这个,就是自动的往weakMap的obj1的map的“name”里面添加方法。函数里面有obj1Proxy.name的就放到obj1->name的数组中去。有obj1Proxy.age的就放到obj1->age的数组(this.reactiveFns)中去.

  class Depend {
    constructor() {
      this.reactiveFns = []
    }

    addDepend(reactiveFn) {
      this.reactiveFns.push(reactiveFn)
    }

    notify() {
      this.reactiveFns.forEach(fn => {
        fn()
      })
    }
  }




  // 对象的响应式
  const obj1 = {
    name: "why", // depend对象
    age: 18 // depend对象
  };
  const obj2 = {
    name: "kobe", // depend对象
    age: 32 // depend对象
  };

  const weakMap = new WeakMap();

  function setDepend(target, key) {
    let targetMap = weakMap.get(target);
    if (!targetMap) {
      targetMap = new Map();
      weakMap.set(target, targetMap);
    }
    let depend = targetMap.get(key);
    if (!depend) {
      depend = new Depend();
      targetMap.set(key, depend)
    }
    return depend
  }



 /*  const objProxy = new Proxy(obj1, {
    get: function (target, key, receiver) {
      return Reflect.get(target, key, receiver)
    },
    set: function (target, key, newVaule, receiver) {
      Reflect.set(target, key, newVaule, receiver);
      setDepend(target, key).notify();
    }
  }) */

  //forEach没有返回值,map有
  let [obj1Proxy, obj2Proxy] =  [obj1, obj2].map(item => {
  return  new Proxy(item, {
      get: function (target, key, receiver) {
        if(activeReactiveFn){
          console.log('watchFn内的调用');
          setDepend(target, key).addDepend(activeReactiveFn);
        }
        return Reflect.get(target, key, receiver)
      },
      set: function (target, key, newVaule, receiver) {
        Reflect.set(target, key, newVaule, receiver);
        setDepend(target, key).notify();
      }
    })
  });


  function obj1NameFn1() {
    console.log(obj1Proxy.name + " obj1NameFn1被执行 ")
    console.log(obj2Proxy.name + " obj1NameFn1被执行 ")
  }

  function obj1NameFn2() {
    console.log(obj1Proxy.name + " obj1NameFn2被执行 ")
  }

  function obj1AgeFn1() {
    console.log(obj1Proxy.age + " obj1AgeFn1被执行 ")
  }

  function obj1AgeFn2() {
    console.log(obj1Proxy.age + " obj1AgeFn2被执行 ")
  }

  function obj2NameFn1() {
    console.log(obj2Proxy.name + " obj2NameFn1被执行 ")
  }

  function obj2NameFn2() {
    console.log(obj2Proxy.name + " obj2NameFn2被执行 ")
  }

  function obj2AgeFn1() {
    console.log(obj2Proxy.age + " obj2AgeFn1被执行 ")
  }

  function obj2AgeFn2() {
    console.log(obj2Proxy.age + " obj2AgeFn2被执行 ")
  }

let activeReactiveFn = null;
function watchFn(fn) {
  activeReactiveFn = fn;
  fn();
  activeReactiveFn = null;
}
/* 
给各个函数分配到obj1/obj2的map里面
*/
watchFn(obj1NameFn1);
watchFn(obj1NameFn2);

watchFn(obj1AgeFn1);
watchFn(obj1AgeFn2);


watchFn(obj2NameFn1);
watchFn(obj2NameFn2);

watchFn(obj2AgeFn1);
watchFn(obj2AgeFn2);



console.log('-----------------------------------------');



console.log(obj1Proxy.name);
obj1Proxy.name = "coder";
obj2Proxy.name = "test";




/* 
obj1Proxy.age = 118;

obj2Proxy.age = 89;

console.log(obj2Proxy.age); */

14.7 对Depend类重构

114.PNG

我们不想让get里面知道有activeReactiveFn这个东西

 get: function (target, key, receiver) {
        if(activeReactiveFn){
          console.log('watchFn内的调用');
          setDepend(target, key).addDepend(activeReactiveFn);
        }
    // 保存当前需要收集的响应式函数
let activeReactiveFn = null

/**
 * Depend优化:
 *  1> depend方法
 *  2> 使用Set来保存依赖函数, 而不是数组[]
 */

 class Depend {
    constructor() {
      this.reactiveFns = new Set()
    }

/*     addDepend(reactiveFn) {
      this.reactiveFns.add(reactiveFn)
    } */

    depend() {
      if(activeReactiveFn){
         // console.log('watchFn内的调用');
          this.reactiveFns.add(activeReactiveFn)
        }
    }

    notify() {
      this.reactiveFns.forEach(fn => {
        fn()
      })
    }
  }




  // 对象的响应式
  const obj1 = {
    name: "why", // depend对象
    age: 18 // depend对象
  };
  const obj2 = {
    name: "kobe", // depend对象
    age: 32 // depend对象
  };

  const weakMap = new WeakMap();

  function setDepend(target, key) {
    let targetMap = weakMap.get(target);
    if (!targetMap) {
      targetMap = new Map();
      weakMap.set(target, targetMap);
    }
    let depend = targetMap.get(key);
    if (!depend) {
      depend = new Depend();
      targetMap.set(key, depend)
    }
    return depend
  }



 /*  const objProxy = new Proxy(obj1, {
    get: function (target, key, receiver) {
      return Reflect.get(target, key, receiver)
    },
    set: function (target, key, newVaule, receiver) {
      Reflect.set(target, key, newVaule, receiver);
      setDepend(target, key).notify();
    }
  }) */

  //forEach没有返回值,map有
  let [obj1Proxy, obj2Proxy] =  [obj1, obj2].map(item => {
  return  new Proxy(item, {
      get: function (target, key, receiver) {
        setDepend(target, key).depend();
        return Reflect.get(target, key, receiver)
      },
      set: function (target, key, newVaule, receiver) {
        Reflect.set(target, key, newVaule, receiver);
        setDepend(target, key).notify();
      }
    })
  });


function watchFn(fn) {
  activeReactiveFn = fn;
  fn();
  activeReactiveFn = null;
}

// watchFn
watchFn(() => {
  console.log(obj1Proxy.name, "-------")
  console.log(obj1Proxy.name, "+++++++")
})
//如果不用set的话,一个函数会被往数组里面加2次。如果一个函数里面有三个obj1Proxy.name,则会被加3次,一次类推

obj1Proxy.name = "kobe";
obj2Proxy.name = "test";
/* 

test.html:150 why -------
test.html:151 why +++++++
test.html:150 kobe -------
test.html:151 kobe +++++++
*/


14.8 对象的响应式操作vue3

把一个对象封装成响应式的

我们目前的响应式是针对于obj一个对象的,我们可以创建出来一个函数,针对所有的对象都可以变成响应式对象:

  // 保存当前需要收集的响应式函数
let activeReactiveFn = null

/**
 * Depend优化:
 *  1> depend方法
 *  2> 使用Set来保存依赖函数, 而不是数组[]
 */

 class Depend {
    constructor() {
      this.reactiveFns = new Set()
    }

    depend() {
      if(activeReactiveFn){
         // console.log('watchFn内的调用');
          this.reactiveFns.add(activeReactiveFn)
        }
    }

    notify() {
      this.reactiveFns.forEach(fn => {
        fn()
      })
    }
  }

  const weakMap = new WeakMap();

  function setDepend(target, key) {
    let targetMap = weakMap.get(target);
    if (!targetMap) {
      targetMap = new Map();
      weakMap.set(target, targetMap);
    }
    let depend = targetMap.get(key);
    if (!depend) {
      depend = new Depend();
      targetMap.set(key, depend)
    }
    return depend
  }


function reactive(obj) {
  return  new Proxy(obj, {
      get: function (target, key, receiver) {
        setDepend(target, key).depend();
        return Reflect.get(target, key, receiver)
      },
      set: function (target, key, newVaule, receiver) {
        Reflect.set(target, key, newVaule, receiver);
        setDepend(target, key).notify();
      }
    })

}

function watchFn(fn) {
  activeReactiveFn = fn;
  fn();
  activeReactiveFn = null;
}



 // 对象的响应式
 const obj1 = {
    name: "why", // depend对象
    age: 18 // depend对象
  };
  const obj2 = {
    name: "kobe", // depend对象
    age: 32 // depend对象
  };

  const obj1Proxy = reactive(obj1);
  const obj2Proxy = reactive(obj2);
  const obj3Proxy = reactive({
    address: "广州市",
    height: 1.88
  })

  // watchFn
watchFn(() => {
  console.log(obj1Proxy.name, "-------")
  console.log(obj1Proxy.name, "+++++++")
})
  obj1Proxy.name = "coderwhy"

  watchFn(() => {
  console.log(obj3Proxy.address)
})

obj3Proxy.address = "北京市";

obj2Proxy.name = "test";
console.log(obj2Proxy.name );

14.9 对象的响应式操作vue2

使用object.definProperty

115.PNG
 // 保存当前需要收集的响应式函数
 let activeReactiveFn = null

/**
 * Depend优化:
 *  1> depend方法
 *  2> 使用Set来保存依赖函数, 而不是数组[]
 */

 class Depend {
    constructor() {
      this.reactiveFns = new Set()
    }

    depend() {
      if(activeReactiveFn){
         // console.log('watchFn内的调用');
          this.reactiveFns.add(activeReactiveFn)
        }
    }

    notify() {
      this.reactiveFns.forEach(fn => {
        fn()
      })
    }
  }

  const weakMap = new WeakMap();

  function setDepend(target, key) {
    let targetMap = weakMap.get(target);
    if (!targetMap) {
      targetMap = new Map();
      weakMap.set(target, targetMap);
    }
    let depend = targetMap.get(key);
    if (!depend) {
      depend = new Depend();
      targetMap.set(key, depend)
    }
    return depend
  }


function reactive(obj) {
   Object.keys(obj).forEach(item => {
    console.log(item);
    let value = obj[item];
    Object.defineProperty(obj, item, {
      get(){
        setDepend(obj, item).depend();
        return value
      },
      set(newValue){
        value = newValue;
        setDepend(obj, item).notify();
      }

    })
  })
  return obj

}

function watchFn(fn) {
  activeReactiveFn = fn;
  fn();
  activeReactiveFn = null;
}



 // 对象的响应式
 const obj1 = {
    name: "why", // depend对象
    age: 18 // depend对象
  };
  const obj2 = {
    name: "kobe", // depend对象
    age: 32 // depend对象
  };

  const obj1Proxy = reactive(obj1);
  const obj2Proxy = reactive(obj2);
  const obj3Proxy = reactive({
    address: "广州市",
    height: 1.88
  })

  // watchFn
watchFn(() => {
  console.log(obj1Proxy.name, "-------")
  console.log(obj1Proxy.name, "+++++++")
})



  obj1Proxy.name = "coderwhy"

  watchFn(() => {
  console.log(obj3Proxy.address)
})

obj3Proxy.address = "北京市";

obj2Proxy.name = "test";
console.log(obj2Proxy.name ); 

上一篇 下一篇

猜你喜欢

热点阅读