vuejs深入浅出读书笔记

183 阅读1分钟

观察者模式

一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统

   // 主题对象
    function Dep(){  
        this.subs = []; //订阅者列表
    }
    // 主题对象通知所有的订阅者
    Dep.prototype.notify=function(){
        this.subs.forEach(function(sub){
            sub.update();
        })
    }
    // 订阅者
    function Sub(x){
         this.x=x;
    }
    Sub.prototype.update=function(){
        this.x=this.x*this.x;
        console.log(this.x)
    }
    //发布者
    var pub={
        publish:function(){
            dep.notify();
        }
    }
    var dep=new Dep();
    // 使用的数组的原型上的方法
    Array.prototype.push.call(dep.subs, new Sub(1), new Sub(2), new Sub(3))
    //发布者发布消息
    pub.publish(); 

对于Vue,我们这里可以认为Vue实例中的data中的每一项属性是一个Dep,而所有用到这个属性的地方都是这个Dep的一个订阅者(sub),当这个属性值变化时,观察者通过监听捕获变化,告诉这个dep去notify每一个订阅者。 以下代码实现党data.a.b.c属性发生改变是时,触发第二个参数中的函数,

class Watcher{
        // expOrFn为data.a.b.c  cb为回调函数
        constructor(vm,expOrFn,cb){
            this.vm=vm;
            this.getter=parsePath(expOrFn);
            this.cb=cb;
            this.value=
            this.get();
        }
        get(){
            window.target=this;
            let value=this.getter.caller(this.vm,this.vm);
            window.target=undefined;
            return value;
        }
        update(){
            const oldValue=this.value;
            this.value=this.get();
            this.cb.call(this.vm,this.value,this.oldValue)
        }
    }

但是上面的代码只是实现了一个属性的变化侦测,我们需要做到的是侦测一个对象中所有的属性,所以需要封装一个Objserver类,也就是给一个数据里边的每一个属性都增加getter和setter属性。

依赖收集

class Dep{
          constructor(){
            this.subs=[];
          }
          addSub(sub){
            this.subs.push(sub)
          }
          removeSub(sub){
              remove(this.subs,sub)
          }
          depend(){
            if(window.target){
               this.addSub(window.target);
            }
          }
          notify(){
              let subs=this.subs.slice();
              for(var i=0;i<subs.length;i++){
                  subs[i].update();
              }
          }
      }
      function remove(arr,sub){
         if(arr.length){
          const index=arr.indexOf(sub);
         if(index>-1){
           return arr.splice(index,1)
         }
         }
      }
      function defineReative(data,key,val){
         let dep=new Dep();
         Object.defineProperty(data,key,{
             enumerable:true,
             configurable:true,
             get:function(){
                 dep.depend();
                 return val;
             },
             set:function(newVal){
                if(val==newVal) {
                    return
                }
                val=newVal;
                dep.notify();
             }
         })
     }

依赖是谁

上面想要收集的是谁?,换句话说,属性变化后应该通知谁?

<!--
 * @Author: your name
 * @Date: 2020-09-24 08:15:44
 * @LastEditTime: 2021-01-28 18:21:44
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \day01c:\vue\objectStudy\index.html
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body></body>
  <script>
    class Dep {
      constructor() {
        this.subs = [];
      }
      addSub(sub) {
        this.subs.push(sub);
      }
      removeSub(sub) {
        remove(this.subs, sub);
      }
      depend() {
        if (window.target) {
          this.addSub(window.target);
        }
      }
      notify() {
        let subs = this.subs.slice();
        for (var i = 0; i < subs.length; i++) {
          subs[i].update();
        }
      }
    }
    function remove(arr, sub) {
      if (arr.length) {
        const index = arr.indexOf(sub);
        if (index > -1) {
          return arr.splice(index, 1);
        }
      }
    }
    let bailRe=/[^\w.$]/;
    function parsePath(path){
        if(bailRe.test(path)){
            return
        }
        const segments=path.split('.');
        return function(obj){
            for(var i=0;i<segments.length;i++){
                if(!obj) return
                obj=obj[segments[i]];
            }
            return obj;
        }
    }
    console.log(parsePath('a.b.c'))

    class Watcher{
        // expOrFn为data.a.b.c  cb为回调函数
        constructor(vm,expOrFn,cb){
            this.vm=vm;
            this.getter=parsePath(expOrFn);
            this.cb=cb;
            this.value=
            this.get();
        }
        get(){
            window.target=this;
            let value=this.getter.caller(this.vm,this.vm);
            window.target=undefined;
            return value;
        }
        update(){
            const oldValue=this.value;
            this.value=this.get();
            this.cb.call(this.vm,this.value,this.oldValue)
        }
    }
    class Observer{
        constructor(value){
           this.value=value;
           if(!Array.isArray(value)){
               this.walk();
           }
        }
        walk(){
            const keys=Object.keys(obj);
            for(var i=0;i<keys.length;i++){
                defineReactive(obj,keys[i],obj[keys[i]])
            }
        }
    }
    function defineReactive(data,key,value){
         if(typeof val==='object'){
             new Observer(val)
         }
         let dep=new Dep();
         Object.defineProperty(data,key,{
             enumerable:true,
             configurable:true,
             get:function(){
                // 订阅
                 dep.depend();
                 return val
             },
             set:function(newVal){
                 if(val==newVal){
                     return
                 }
                 val=newVal;
                 dep.notify();
             }
         })
    }
  </script>
</html>