skip to content
天真笔录

vue响应式

/ 2 min read

响应式入口

src / core / instance / state.js;
function initState(vm) {
	const opts = vm.$options;
	if (opts.props) initProps(vm, opts.props);
	if (opts.methods) initMethods(vm, opts.methods);
	if (opts.data) {
		initData(vm);
	} else {
		observe((vm._data = {}), true /* asRootData */);
	}
	if (opts.computed) initComputed(vm, opts.computed);
	if (opts.watch && opts.watch !== nativeWatch) {
		initWatch(vm, opts.watch);
	}
}
  • 通过上面initState函数得知 props,methods,data的顺序

    props、methods、data、computed、watch

initData

let data = vm.$options.data;
observe(data);

响应式处理

// src/core/observer/index.js
function observe(value) {
	new Observe(value);
}
class Observe {
	constructor(value) {
		this.value = value;
		// 数组处理
		if (Array.isArray(value)) {
			if (hasProto) {
				protoAugment(value, arrayMethods);
			} else {
				copyAugment(value, arrayMethods, arrayKeys);
			}
		} else {
			// 对象处理
			this.walk(value);
		}
	}

	walk(obj) {
		const keys = Object.keys(obj);
		for (let i = 0; i < keys.length; i++) {
			defineReactive(obj, keys[i]);
		}
	}
}

响应式核心函数

function defineReactive(obj, key) {
	const dep = new Dep(); // 每一个key对应一个Dep实例

	let childOb = observe(val); // 递归遍历对象嵌套
	Object.defineProperty(obj, key, {
		get() {
			// obj上是否存在自定义get,如果没有则取obj[key]
			const value = getter ? getter.call(obj) : obj[key];
			if (Dep.target) {
				dep.depend(); // 依赖收集
				if (childOb) {
					childOb.dep.depend(); // 子依赖收集
					if (Array.isArray(value)) {
						dependArray(value); // 处理数组依赖
					}
				}
			}
			return value;
		},
	});
}

Dep

// src/core/observer/dep.js
class Dep {
  constructor() {
    this.subs = []
  }
  addSub(sub) {
    this.subs.push(sub)
  }

  depend() {
    if (Dep.target) {
      Dep.target.addDep(this)
      // 1. defineReactive执行depend里却调用了watcher的addDep,
      // 2. 在addDep中把dep保存到watcher里(this.newDeps.push(dep))
      // 3. 然后又调用了dep.addSub(this)把watcher保存到dep中,实在是骚的一批
    }
  }
}
Dep.target = null
const targetStack = [] // 保存的是watcher
// 在watcher中调用pushTarget
export function pushTarget (target: ?Watcher) {
  targetStack.push(target)
  Dep.target = target // target为watcher实例,在上面defineReactive中通过dep.depend()把watcher收集到dep中
}

watcher详情