# state

这一节主要对数据进行响应式处理和添加依赖追踪

# _init方法

主要对传入的选项进行处理,这里我们只处理,data 和 computed 属性

export function stateMixin(Vue) {
	Vue.prototype._init = function () {
		initState(this);
        initComputed(this);
	};
}

# initState

初始化data数据对象,做了以下几件事情

  • 将选项数据传递给别名 _data
  • 遍历_data数据,代理到当前实例,方便 vm.xx 的调用
  • 执行observer,添加响应式依赖
function initState(vm) {
	const data = (vm._data = vm.$options.data);

	// proxy data
	Object.keys(data).forEach((key) => {
		proxy(vm, '_data', key);
	});

	// observe data
	observe(data);
}

function proxy(obj, srcKey, key) {
	Object.defineProperty(obj, key, {
		enumerable: true,
		configurable: true,
		get: function proxyGetter() {
			return this[srcKey][key];
		},
		set: function proxySetter(val) {
			this[srcKey][key] = val;
		},
	});
}

当访问 vm.count 时,实际访问的是 vm._data.count,源码中做了重复性探测处理,避免属性重复

# computed

对 computed 的处理,类似于data,遍历所有属性,不同的是,内部添加了watcher,来追踪变化,实际上 computed 的value实际上是所依赖 watcher 的 value

function initComputed(vm) {
  const computed = vm.$options.computed;
  const watchers = vm._computedWatchers = Object.create(null);

  for (let key in computed) {
    const getter = computed[key];

    watchers[key] = new Watcher(
      vm,
      getter,
      noop,
      { key, type: 'computed' }
    );

    defineComputed(vm, key, getter);
  }
  // console.log('watchers', vm._computedWatchers===watchers);
}

接着实现 defineComputed,来实现 getter,返回数据,这里是调用了个高级方法来返回 getter,实际代码里,还兼容了 SSR的情形,SSR里直接调用传递的方法 实际还有 setter的情形,即可以设置数据,不一定只是获取数据


function defineComputed(vm, key, getter) {
  console.log('defineComputed', key);
  const def = {
    enumerable: true,
    configurable: true,
    get: makeComputedGetter(vm, key)
  };

  Object.defineProperty(vm, key, def);
}

function makeComputedGetter(vm, key) {
  return function computedGetter() {
      const watcher = vm._computedWatchers[key];
      // 添加当前依赖
      if (Dep.target) {
        watcher.depend();
      }
      console.log('computedGetter', watcher);
      return watcher.value;
    }
}

watcher, observe的实现在后面再详细介绍

上次更新于: 5/11/2022, 1:26:34 PM