vue (2.X) 响应式原理

896 阅读1分钟

vue的响应式原理的核心是什么

vue2 中实现响应式只要依靠 Object.defineProperty进行数据劫持,以达到响应式的目的

  class Vue {
      constructor(options) {
        this.$options = options;
    
        // 数据响应化
        this.$data = options.data;
        this.observe(this.$data);
    
        // 模拟一下watcher创建
        // new Watcher();
        // // 通过访问test属性触发get函数,添加依赖
        // this.$data.test;
        // new Watcher();
        // this.$data.foo.bar;
    
        // new Compile(options.el, this);
    
        // created执行
        if (options.created) {
            options.created.call(this);
        }
      }
    
      observe(value) {
        if (!value || typeof value !== "object") {
          return;
        }
    
        // 遍历该对象
        Object.keys(value).forEach(key => {
          this.defineReactive(value, key, value[key]);
          //代理data中的属性到vue实例上
          this.proxyData(key);
        });
      }
    
      // 数据响应化
      defineReactive(obj, key, val) {
        this.observe(val); // 递归解决数据嵌套
    
        const dep = new Dep();
    
        Object.defineProperty(obj, key, {
          get() {
            Dep.target && dep.addDep(Dep.target);
            return val;
          },
          set(newVal) {
            if (newVal === val) {
              return;
            }
            val = newVal;
            // console.log(`${key}属性更新了:${val}`);
            dep.notify();
          }
        });
      }
      
    proxyData(key) {
        Object.defineProperty(this, key, {
          get(){
            return this.$data[key]
          },
          set(newVal){
            this.$data[key] = newVal;
          }
        })
    }
}

// Dep:用来管理Watcher
class Dep {
  constructor() {
    // 这里存放若干依赖(watcher)
    this.deps = [];
  }

  addDep(dep) {
    this.deps.push(dep);
  }

  notify() {
    this.deps.forEach(dep => dep.update());
  }
}

// Watcher
class Watcher {
  constructor(vm, key, cb) {
      this.vm = vm;
      this.key = key;
      this.cb = cb;

    // 将当前watcher实例指定到Dep静态属性target
    Dep.target = this;
    this.vm[this.key]; // 触发getter,添加依赖
    Dep.target = null;
  }

  update() {
    // console.log("属性更新了");
    this.cb.call(this.vm, this.vm[this.key]);
  }
}

observe 是观察者,专门遍历对象中的所有属性,将对象属性传入defineReactive做下一步处理

defineReactive 函数内部实现了数据的响应化,在函数内部 const dep = new Dep(); 专门在get()里进行依赖收集,在set()里判断属性的值是否变化,变化的话调用dep.notify() 来通知更新

Class Dep 是专门用来管理watcher的而 watcher 是专门监听数据的,实现数据的动态更新