vue源码解析data与watcher

以一份简单的例子说明:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src='node_modules/vue/dist/vue.js' type='text/javascript'></script>

</head>
<body>
<div id='app'></div>
<script type='text/javascript'>
    var vueIns=new Vue({
      data(){
        return {
          aaa:1,
          bbb:2
        }
      },
      created(){
        this.aaa =3
      },
      methods:{
        confirm(){
          this.bbb=333
        }
      },
      template:'<div><h1>{{aaa}}</h1><h2>{{bbb}}</h2></div>'
    }).$mount('#app')
    console.log(vueIns)
</script>
</body>
</html>

 Vue对象中的data对象

Observer.prototype.walk = function walk (obj) {
    var keys = Object.keys(obj);
    for (var i = 0; i < keys.length; i++) {
      defineReactive$$1(obj, keys[i]);
    }
};

/**
 * Define a reactive property on an Object.
 */
  function defineReactive$$1 (
    obj,
    key,
    val,
    customSetter,
    shallow
  ) {
    var dep = new Dep();

    var property = Object.getOwnPropertyDescriptor(obj, key);
    if (property && property.configurable === false) {
      return
    }

    // cater for pre-defined getter/setters
    var getter = property && property.get;
    var setter = property && property.set;
    if ((!getter || setter) && arguments.length === 2) {
      val = obj[key];
    }

    var childOb = !shallow && observe(val);
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      get: function reactiveGetter () {
        var value = getter ? getter.call(obj) : val;
        if (Dep.target) {
          dep.depend();
          if (childOb) {
            childOb.dep.depend();
            if (Array.isArray(value)) {
              dependArray(value);
            }
          }
        }
        return value
      },
      set: function reactiveSetter (newVal) {
        var value = getter ? getter.call(obj) : val;
        /* eslint-disable no-self-compare */
        if (newVal === value || (newVal !== newVal && value !== value)) {
          return
        }
        /* eslint-enable no-self-compare */
        if (customSetter) {
          customSetter();
        }
        // #7981: for accessor properties without setter
        if (getter && !setter) { return }
        if (setter) {
          setter.call(obj, newVal);
        } else {
          val = newVal;
        }
        childOb = !shallow && observe(newVal);
        dep.notify();
      }
    });
  }

将_data的数据进行遍历defineProperty

得到:vm.aaa的形式

 

_data:
   aaa: 3
   bbb: 2
   __ob__: Observer {value: {…}, dep: Dep, vmCount: 1}
   get aaa: ƒ reactiveGetter()
   set aaa: ƒ reactiveSetter(newVal)
   get bbb: ƒ reactiveGetter()
   set bbb: ƒ reactiveSetter(newVal)

代理:proxy方法

proxy(vm, "_data", key); 

function proxy (target, sourceKey, key) {
    sharedPropertyDefinition.get = function proxyGetter () {
      return this[sourceKey][key]
    };
    sharedPropertyDefinition.set = function proxySetter (val) {
      this[sourceKey][key] = val;
    };
    Object.defineProperty(target, key, sharedPropertyDefinition);
  }

  得到

aaa: 3
bbb: 2

__proto__: Object
   get aaa: ƒ proxyGetter()
   set aaa: ƒ proxySetter(val)
   get bbb: ƒ proxyGetter()
   set bbb: ƒ proxySetter(val)

  

数据监控执行

initWatch

 function initWatch (vm, watch) {
    for (var key in watch) {
      var handler = watch[key];
      if (Array.isArray(handler)) {
        for (var i = 0; i < handler.length; i++) {
          createWatcher(vm, key, handler[i]);
        }
      } else {
        createWatcher(vm, key, handler);
      }
    }
  }

  function createWatcher (
    vm,
    expOrFn,
    handler,
    options
  ) {
    if (isPlainObject(handler)) {
      options = handler;
      handler = handler.handler;
    }
    if (typeof handler === 'string') {
      handler = vm[handler];
    }
    return vm.$watch(expOrFn, handler, options)
  }


   Vue.prototype.$watch = function (
      expOrFn,
      cb,
      options
    ) {
      var vm = this;
      if (isPlainObject(cb)) {
        return createWatcher(vm, expOrFn, cb, options)
      }
      options = options || {};
      options.user = true;
      var watcher = new Watcher(vm, expOrFn, cb, options);
      if (options.immediate) {
        try {
          cb.call(vm, watcher.value);
        } catch (error) {
          handleError(error, vm, ("callback for immediate watcher \"" + (watcher.expression) + "\""));
        }
      }
      return function unwatchFn () {
        watcher.teardown();
      }
    };
  }

 

posted @ 2020-10-09 20:52  莺哥  阅读(253)  评论(0编辑  收藏  举报