// initDataconst data = { msg: 'msg' }observe(data)
// observefunction observe(data) {if (!isObject(value)) return;return new Observer(data)}
// Class Observeclass Observe {value: any;dep: Dep;vmCount: number;constructor (data) {this.value = datathis.dep = new Dep()this.vmCount = 0data._ob_ = thisthis.walk(data)}walk(obj) {const keys = Object.keys(obj)for (let i = 0; i < keys.length; i++) {defineReactive(obj, keys[i])}}}// 这一步完成之后会将我们data定义一个_ob_属性 说明以及做过响应式处理
class Dep {static target: ?Watcher;id: number;subs: Array<Watcher>;constructor () {this.id = uid++this.subs = []}addSub (sub: Watcher) {this.subs.push(sub)}removeSub (sub: Watcher) {remove(this.subs, sub)}depend () {if (Dep.target) {Dep.target.addDep(this) // watcher 添加对应的dep}}notify () {const subs = this.subs.slice()for (let i = 0, l = subs.length; i < l; i++) {subs[i].update() // 调用对应的watcher更新}}}
function defineReactive(obj, key) {const dep = new Dep()let childOb = observe(val) // 子对象 { msgData: {msg: ''} } => observe({ msg: ''})Object.defineProperty(obj, key,{get() {if (Dep.target) {dep.depend() // watcher实例 添加对应的dep}if (childOb) {childOb.dep.depend()}retun obj[key]},set(newVal) {val = newValchildOb = observe(newVal)dep.notify()}})}
// 假设一个data为以下数据const data = {msg: 'msg',formData: {name: 'zyh'}};// 进行过响应式过后为:const data = {msg: 'msg',formData: {name: 'zyh',_ob_: Observe{ value: formData, dep: Dep }},_ob_: Observe{ value: data, dep: Dep }};
何时触发get呢?
接着手动调用$mount(‘#app’)
Vue.prototype.$mount = function(el) {const options = this.$optionsconst { render, staticRenderFns } = compileToFunctions(template) // 生成render函数return mount.call(this, el, hydrating)}
Vue.prototype.$mount = function(el) {return mountComponent(this, el)}
function mountComponent(vm, el) {vm.$el = elif (!vm.$options.render) vm.$options.render = createEmptyVNode // 生成一个空节点let updateComponent = () => {vm._update(vm._render(), hydrating)}new Watcher(vm, updateComponent, ()=>{}, {}, true /* isRenderWatcher */)}
class Watcher {constructor(vm: Component,expOrFn: string | Function,cb: Function,options?: ?Object,isRenderWatcher?: boolean) {this.vm = vmif (isRenderWatcher) {vm._watcher = this}vm._watchers.push(this)this.getter = expOrFn // updateComponentthis.value = this.get()}get() {const vm = this.vmvalue = this.getter.call(vm, vm) // 开始执行 vm._update(vm._render(), hydrating)}}
vm._update 在哪定义呢 lifecycleMixin
Vue.prototype._update
梳理下流程:
- 定义响应式数据
 - 执行挂载
 - 生成render函数
 - 执行mountComponent函数
 - new Wather
 - wather 内部调用get Dep.target = this(watcher)
 - wather 内部调用vm._update(vm._render(), hydrating)
 - 调用render函数生成vnode,这一步触发 getter 依赖收集Dep.targe(wather)
 - set触发dep.notify ```typescript const data = { obj: { foo: { bar: ‘bar’ } }, name: ‘kobe’ }
 
// 1. this.data.obj = this.obj this.data.name = this.name // 2. this.obj getter 触发getter 的 依赖收集 // 3. this.obj.foo // // 4. 赋值触发setter
```typescriptdep.depend Dep.target:watcher// class Dep// 目的还是添加watcherdepend () {if (Dep.target) {Dep.target.addDep(this)}}addSub (watcher) {this.subs.push(sub)}// class WatcheraddDep (dep: Dep) {const id = dep.idif (!this.newDepIds.has(id)) {this.newDepIds.add(id)this.newDeps.push(dep)if (!this.depIds.has(id)) {dep.addSub(this)}}}
// 对数组的原型方法进行拦截扩展protoAugment(value, arrayMethods) // value: []const arrayMethods = Object.create(Array.prototype)function protoAugment (target, src: Object) {/* eslint-disable no-proto */target.__proto__ = src/* eslint-enable no-proto */}const methodsToPatch = ['push','pop','shift','unshift','splice','sort','reverse']/*** Intercept mutating methods and emit events*/methodsToPatch.forEach(function (method) {// cache original methodconst original = arrayProto[method]def(arrayMethods, method, function mutator (...args) {const result = original.apply(this, args)const ob = this.__ob__let insertedswitch (method) {case 'push':case 'unshift':inserted = argsbreakcase 'splice':inserted = args.slice(2)break}if (inserted) ob.observeArray(inserted)// notify changeob.dep.notify()return result})})
