vue2.0源码调试过程记录---主要initState包括data响应式属性等过程

10 篇文章 0 订阅

记录一下vue源码调试的过程!只为学习!

  function Vue (options) {
    if (!(this instanceof Vue)
    ) {
      warn('Vue is a constructor and should be called with the `new` keyword');
    }
    // 从这里的init开始调试!!!!
    this._init(options);
  }

只截取了部分源码,把我没有看到的部分暂时先舍去了。上面的init就是下面的initMixin方法里面的**_init**方法,ok,继续看下去

  function initMixin (Vue) {
    Vue.prototype._init = function (options) {
      var vm = this;
      // a uid
      vm._uid = uid$3++;
      // a flag to avoid this being observed
      vm._isVue = true; 
      {
        initProxy(vm);
      }
      // expose real self
      vm._self = vm;
      initLifecycle(vm);
      initEvents(vm);
      initRender(vm);
      callHook(vm, 'beforeCreate');
      initInjections(vm); // resolve injections before data/props
      // 初始化状态,并对数据进行观察
      initState(vm);
      initProvide(vm); // resolve provide after data/props
      callHook(vm, 'created')

      if (vm.$options.el) {
        vm.$mount(vm.$options.el);
      }
    };
  }

第一条线:看一下initRender过程

 function initRender (vm) {
    vm._vnode = null; // the root of the child tree
    vm._staticTrees = null; // v-once cached trees
    var options = vm.$options;
    var parentVnode = vm.$vnode = options._parentVnode; 
    var renderContext = parentVnode && parentVnode.context;
    vm.$slots = resolveSlots(options._renderChildren, renderContext);
    vm.$scopedSlots = emptyObject;
    // 这里的_c其实是对createElement方法的使用,vue中很多通过_小写字母来代理一些原生方法
    vm._c = function (a, b, c, d) { return createElement(vm, a, b, c, d, false); };
    vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };
    var parentData = parentVnode && parentVnode.data;
    /* istanbul ignore else */
    // 将$attrs和$listeners 通过defineReactive$$1 变成响应式
    {
      defineReactive$$1(vm, '$attrs', parentData && parentData.attrs || emptyObject, function () {
        !isUpdatingChildComponent && warn("$attrs is readonly.", vm);
      }, true);
      defineReactive$$1(vm, '$listeners', options._parentListeners || emptyObject, function () {
        !isUpdatingChildComponent && warn("$listeners is readonly.", vm);
      }, true);
    }
  }

第二条线:①initState,相对比较重要的一条线

  function initState (vm) {
    vm._watchers = [];
    if (opts.data) {
      // 初始化data的时候,对data进行了数据代理,和observe动作
      initData(vm);
    } else {
      observe(vm._data = {}, true /* asRootData */);
    }
  }

然后到initState里面之后,在看一下②initData方法

// 初始化数据data
  function initData (vm) {
    var data = vm.$options.data;
    // 在getData中是对data函数的调用,生成了obj对象
    data = vm._data = typeof data === 'function'
      ? getData(data, vm)
      : data || {};
      // 判断data函数是否返回一个对象obj,如果不返回一个obj,则报警告warn
    if (!isPlainObject(data)) {
      data = {};
      warn(
        'data functions should return an object:\n' +
        'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
        vm
      );
    }
    // proxy data on instance
    var keys = Object.keys(data);
    var props = vm.$options.props;
    var methods = vm.$options.methods;
    var i = keys.length;
    // 通过while循环,遍历对象dataObj,并对dataObj的每一个属性通过Object.defineProperty变成响应式属性
    while (i--) {
      var key = keys[i];
      {
        if (methods && hasOwn(methods, key)) {
          warn(
            ("Method \"" + key + "\" has already been defined as a data property."),
            vm
          );
        }
      }
      if (props && hasOwn(props, key)) {
        warn(
          "The data property \"" + key + "\" is already declared as a prop. " +
          "Use prop default value instead.",
          vm
        );
      } else if (!isReserved(key)) {
        // 代理data数据
        proxy(vm, "_data", key);
      }
    }
    // observe data
    // 对数据data进行observe,如果对象__ob__上有数据,说明该对象已经有了observe,直接返回
    observe(data, true /* asRootData */);
  }

接着看一下③observe方法

  function observe (value, asRootData) {
    if (!isObject(value) || value instanceof VNode) {
      return
    }
    var ob;
    if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
      ob = value.__ob__;
    } else if (
      shouldObserve &&
      !isServerRendering() &&
      (Array.isArray(value) || isPlainObject(value)) &&
      Object.isExtensible(value) &&
      !value._isVue
    ) {
    // 实际上会走这个分支
      ob = new Observer(value);
    }
    if (asRootData && ob) {
      ob.vmCount++;
    }
    return ob
  }

接下来看一下这个**④new Observer()**的过程
观察者类

var Observer = function Observer (value) {
    this.value = value;
    this.dep = new Dep();
    this.vmCount = 0;
    // 给传入的data对象添加一个响应式的属性__ob__,值就是这个observer
    def(value, '__ob__', this);
    if (Array.isArray(value)) {
      if (hasProto) {
        protoAugment(value, arrayMethods);
      } else {
        copyAugment(value, arrayMethods, arrayKeys);
      }
      this.observeArray(value);
    } else {
    // 当value是一个array的时候,走上面,不是array,走这个walk方法
      // 在walk方法里,对value的属性进行响应式属性的设置
      this.walk(value);
    }
  };

瞅瞅这个⑤walk方法,看起来相对简单,实际上就是对data生成的obj遍历,对属性进行响应式的处理

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

最后贴一下这个⑥defineReactive$$1方法

  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();
      }
    });
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值