1.初始化部分
function Vue(options) {
if (!(this instanceof Vue)) {
warn("Vue is a constructor and should be called with the `new` keyword");
}
this._init(options);
}
Vue.prototype._init = function (options) {
...
initLifecycle(vm);
initEvents(vm);
initRender(vm);
callHook(vm, "beforeCreate");
initInjections(vm);
initState(vm); //主要部分
initProvide(vm);
callHook(vm, "created");
...
}
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 /* asRootData */);
}
if (opts.computed) {
initComputed(vm, opts.computed);
}
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch);
}
}
2.Data初始化
function initData(vm) {
var data = vm.$options.data;
//首先获取了组件的 data 选项,如果 data 是一个函数,则调用该函数获取数据对象
data = vm._data =
typeof data === "function" ? getData(data, vm) : data || {};
// getData -> data.call(vm, vm)
// data 不是一个纯对象-通过{}或new创建的对象,则会发出警告
if (!isPlainObject(data)) { //toString.call(data) === "[object Object]"
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 (i--) {
var key = keys[i];
// 判断是否和method以及props命名冲突
{
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)) {
// 遍历 vm._data 中的每个属性,并使用 proxy 函数将它们代理到 vm 上
// 可以通过 vm.propertyName 访问 vm._data.propertyName
proxy(vm, "_data", key);
}
}
// 使用 observe 函数观察数据对象,以便在数据发生更改时能够捕获更改
observe(data, true /* asRootData */);
}
3.观察者
该部分用于创建一个观察者实例用于监听对象发生变化,来达到数据变化的时候触发视图的更新
function observe(value, asRootData) {
if (!isObject(value) || value instanceof VNode) {
// 检查传入的值是否是一个对象,如果不是或者这个值是一个 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 //当前不是vue实例
) {
ob = new Observer(value);
}
if (asRootData && ob) {
ob.vmCount++;
}
return ob;
}
function Observer(value) {
this.value = value; // 观察的对象
this.dep = new Dep();// 创建一个新的 Dep 对象,该对象用于收集依赖
this.vmCount = 0;
def(value, "__ob__", this); // 标记当前值是Observer实例
// 判断是否数组
if (Array.isArray(value)) {
// 判断是否有__proto__属性
if (hasProto) {
protoAugment(value, arrayMethods);
} else {
copyAugment(value, arrayMethods, arrayKeys);
}
// 改写数组原型 push/pop等七个方法 如果调用这些方法会触发dep.notify以达到试图更新的效果
this.observeArray(value);
} else {
this.walk(value);
}
};
function walk(obj) {
//如果是对象进行遍历 对每个属性定义getter和setter
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i]);
}
};
function defineReactive(obj, key, val, customSetter, shallow) {
var dep = new Dep();
...
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {// 防止多次添加Watcher
dep.depend(); // 此处为添加Watcher 需结合Watcher部分一起看后面会再提到这部分
...
}
return value;
},
set: function reactiveSetter(newVal) {
var value = getter ? getter.call(obj) : val;
if (newVal === value || (newVal !== newVal && value !== value)) {
return;
}
...
if (getter && !setter) {
return;
}
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
dep.notify(); // 数据变化时 遍历执行之前depend的Watcher
//需结合Watcher部分一起看后面会再提到这部分
},
});
4.Watcher部分
updateComponent = function () {
// 此处为更新试图的实现
// vm.render生成虚拟节点 其中涉及获取data中的数据从而触发之前观察者部分中对象属性的getter函数
vm._update(vm._render(), hydrating);
};
// 渲染Wachter
new Watcher(
vm,
updateComponent,
noop,
{
before: function before() {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, "beforeUpdate");
}
},
},
true /* isRenderWatcher */
);
var Watcher = function Watcher(vm, expOrFn, cb, options, isRenderWatcher) {
this.vm = vm;
... //此处省略代码,仅显示关键内容
if (typeof expOrFn === "function") {
this.getter = expOrFn; // 将前面更新试图的实现赋值给getter
}
this.value = this.lazy ? undefined : this.get(); // 调用get() (lazy为计算属性用到的watcher)
};
function get() {
pushTarget(this);
// pushTarget的实现如下 结合之前getter函数的if(Dep.target)
//function pushTarget(target) {
// targetStack.push(target);
// Dep.target = target; //target为当前Watcher
// }
var value;
var vm = this.vm;
try {
value = this.getter.call(vm, vm); //此处调用后导致触发之前观察者部分中对象属性的getter函数
} catch (e) {
...
} finally {
...
popTarget(); // 此处为删除 目的是防止每次访问数据都进行依赖收集
this.cleanupDeps();
}
return value;
};
// 然后回到getter函数中的dep.depend()
Dep.prototype.depend = function depend() {
if (Dep.target) {
Dep.target.addDep(this); //此处实际调用的是Watcher中的addDep函数 此处this是dep实例
}
};
Watcher.prototype.addDep = function addDep(dep) {
var id = dep.id;
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id);
this.newDeps.push(dep);
if (!this.depIds.has(id)) {
dep.addSub(this); // 此处实际调用的dep原型上的addSub函数 此处this为Watcher实例
}
}
};
var Dep = function Dep() {
// 该构造函数在之前遍历data的对象属性时会执行
this.id = uid++;
this.subs = [];
};
Dep.prototype.addSub = function addSub(sub) {
this.subs.push(sub);
// subs为执行构造函数Dep是的属性
};
// 所以绕了一圈 vue最终达到的效果是为每个遍历的属性添加Watcher实例
Dep.prototype.notify = function notify() {
// stabilize the subscriber list first
var subs = this.subs.slice();
if (!config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort(function (a, b) {
return a.id - b.id;
});
}
for (var i = 0, l = subs.length; i < l; i++) {
subs[i].update();
}
};
Watcher.prototype.update = function update() {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true;
} else if (this.sync) {
this.run();
} else {
queueWatcher(this); // 将watcher推入队列
//queueWatcher -> nextTick(flushSchedulerQueue); 会在下一次dom更新时执行,期间经过很多操作,最终会调用watcher的run方法
}
};
*/
Watcher.prototype.run = function run() {
if (this.active) {
var value = this.get(); // 完成试图的更新
}
...
}