1.初始化阶段
function initState(vm) {
vm._watchers = [];
var 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 );
}
if (opts.computed) {
initComputed(vm, opts.computed); <-- 进入computed初始化
}
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch);
}
}
function initComputed(vm, computed) {
var watchers = (vm._computedWatchers = Object.create(null));
// 创建一个对象用来存储所有计算属性的watcher
var isSSR = isServerRendering();
for (var key in computed) {
var userDef = computed[key];
var getter = typeof userDef === "function" ? userDef : userDef.get;
// 计算属性的两种写法 函数/对象(get/set)
if (getter == null) {
warn('Getter is missing for computed property "' + key + '".', vm);
}
if (!isSSR) {
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions //-> {lazy:true}
);
}
if (!(key in vm)) {
defineComputed(vm, key, userDef);
} else {
if (key in vm.$data) {
warn(
'The computed property "' + key + '" is already defined in data.',
vm
);
} else if (vm.$options.props && key in vm.$options.props) {
warn(
'The computed property "' + key + '" is already defined as a prop.',
vm
);
}
}
2.响应式实现
var sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop,
};
function defineComputed(target, key, userDef) {
var shouldCache = !isServerRendering();
if (typeof userDef === "function") {
sharedPropertyDefinition.get = shouldCache
? createComputedGetter(key)
: createGetterInvoker(userDef);
sharedPropertyDefinition.set = noop;
} else {
sharedPropertyDefinition.get = userDef.get
? shouldCache && userDef.cache !== false
? createComputedGetter(key)
: createGetterInvoker(userDef.get)
: noop;
sharedPropertyDefinition.set = userDef.set || noop;
}
if (sharedPropertyDefinition.set === noop) {
sharedPropertyDefinition.set = function () {
warn(
'Computed property "' +
key +
'" was assigned to but it has no setter.',
this
);
};
}
Object.defineProperty(target, key, sharedPropertyDefinition);
}
function createComputedGetter(key) {
return function computedGetter() {
var watcher = this._computedWatchers && this._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {
watcher.evaluate();
}
if (Dep.target) {
watcher.depend();
}
return watcher.value;
}
};
}
Watcher.prototype.update = function update() {
if (this.lazy) {
this.dirty = true;
}
...
}
Watcher.prototype.evaluate = function evaluate() {
this.value = this.get();
this.dirty = false;
};