vue 源码理解分解之数据绑定

Observer , dep , watcher 是vue双向绑定的关键组成部分

observer

方法、类作用
toggleObserving (value: boolean)控制变量“shouldObserve”,间接控制调用observer时是否为对象创建__ob__
class Observer(value:object | any[])创建 {value,dep,vmCount}
observe (value: any, asRootData: ?boolean): Observer | void为value创建ob
defineReactive(obj: any,key: string,val?: any,customSetter?: Function,shallow?: boolean)将obj中的key定义为响应式
set(target: any[] | any, key: string | number, val: any) :any为对象设值,如果是reactiveObj则触发通知
del(target:any | any[], key: any)删除属性触发修改
// 控制着observer是否能生成 ob 对象
export function toggleObserving (value: boolean) {
  shouldObserve = value
}

// 为value 新增__ob__ ,每个ob关联一个dep 
// value为数组时会修改其原型链上的方法,使其某些方法可以触发更新,并为其每个元素进行 observer
// value是对象则会针对每个值 defineReactive
export class Observer {
  value: any;
  dep: Dep;
  vmCount: number; // number of vms that have this object as root $data
  constructor (value: any) {}
  
  walk (obj: Object) {}
  observeArray (items: Array<any>) {}
}

// 由shouldObserve 与类型判断控制是否生成 ob , 如果生成或已有ob,则返回
export function observe (value: any, asRootData: ?boolean): Observer | void {}

/**
 * Define a reactive property on an Object.
 * 配置obj[key]属性为响应式,会获取其原本的 getter, setter
 * 响应式的属性当被取值时(getter),会检查全局target,如果当前被watch了,则会收集watcher,如果val是数组则会让每个元素都一并收集
 * 响应式的属性当被赋值时(setter(val))会通知所有收集的watcher 
 * 注:当对obj不存在的key进行响应式时,将会没有getter,setter,只改闭包中的值
 */
export function defineReactive(
  obj: any,
  key: string,
  val?: any,
  customSetter?: Function,
  shallow?: boolean
) {}

/**
 * Set a property on an object. Adds the new property and
 * triggers change notification if the property doesn't
 * already exist.
 * 更改obj/arr或新增响应式属性
*/
export function set(target: any[] | any, key: string | number, val: any) :any {}

/**
 * Delete a property and trigger change if necessary.
 */
export function del(target:any | any[], key: any) {}

Dep

方法/类作用
class Dep依赖收集器,收集watcher
pushTargetwatcher 入栈
popTargetwacher出栈
let uid = 0
export default class Dep {
  static target: WatcherInstance | null;
  id: number;
  subs: Array<WatcherInstance>;
  constructor() {
    this.id = uid++
    this.subs = []
  }
  addSub(sub: WatcherInstance) {
    this.subs.push(sub)
  }
  removeSub(sub: WatcherInstance) {
    remove(this.subs, sub)
  }
  depend() {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }
  // 为subs中的wacher根据ID排序(dev), 触发所有wacher的update()
  notify () {}
}

Dep.target = null
// watcher 栈
const targetStack = <WatcherInstance[]>[];
export function pushTarget(target: WatcherInstance | null) {}
export function popTarget() {}

Watcher

方法/类作用
class Watcher观察者,掌握着触发的回调
let uid = 0
export default class Watcher {
  vm: Component;
  expression: string;
  cb: (value?: any, oldValue?: any) => void;
  id: number;
  // options
  deep: boolean;
  user: boolean;
  lazy: boolean;
  sync: boolean;
  dirty: boolean;
  //状态
  active: boolean;
  // 记录着被哪些依赖收集
  deps: Array<Dep>;
  newDeps: Array<Dep>;
  depIds: SimpleSet;
  newDepIds: SimpleSet;
  before?: Function;
  getter: () => any;
  value: any;
  constructor(
    vm: Component,
    expOrFn: string | Function,
    cb: (value?: any, oldValue?: any) => void,
    options?: WatcherOption | void,
    isRenderWatcher?: boolean
  ) {
 	// ...
  	this.value = this.lazy
      ? undefined
      : this.get()
  }
  /**
   * Evaluate the getter, and re-collect dependencies.
   * 当前watcher入栈,获取expOrFn 对应的值,并且让其内部的响应式属性收集当前watcher,形成绑定关系
   */
  get(): any {
  	pushTarget(this);
  	value = this.getter.call(vm, vm)
  	if (this.deep) {
        traverse(value)
    }
    popTarget()
    this.cleanupDeps()
    return value
  }
	
  /**
   * Add a dependency to this directive.
   */
  addDep(dep: DepInstance) {}
  
  /**
   * Clean up for dependency collection.
   * 清除久依赖,将新依赖转为旧依赖
   */
  cleanupDeps() {}
  
  /**
   * Subscriber interface.
   * Will be called when a dependency changes.
   * 三种情况更新
   */
  update() {
	/* istanbul ignore else */
    if (this.lazy) {
      this.dirty = true;
    } else if (this.sync) {
      this.run();
    } else {
      queueWatcher(this);
    }
  }
	
  /**
   * Scheduler job interface.
   * Will be called by the scheduler.
   * 触发 get() 更新 value , 并触发 cb.call(vm,val,oval) (cb对于RenderWatcher无意义)
   */
  run() {}
	
 /**
  * Evaluate the value of the watcher.
  * This only gets called for lazy watchers.
  */
  evaluate() {
    this.value = this.get()
    this.dirty = false
  }
	
  /**
   * Depend on all deps collected by this watcher.
   */
  depend() {
    let i = this.deps.length
    while (i--) {
      this.deps[i].depend()
    }
  }
  
  /**
  * Remove self from all dependencies' subscriber list.
  */
  teardown() {
	if (this.active) {
      // remove self from vm's watcher list
      // this is a somewhat expensive operation so we skip it
      // if the vm is being destroyed.
      if (!this.vm._isBeingDestroyed) {
        remove(this.vm._watchers, this)
      }
      let i = this.deps.length
      while (i--) {
        this.deps[i].removeSub(this)
      }
      this.active = false
    }
  }
}

traverse

方法/类作用
traverse(val: any)遍历对象(收集当前target),如果存在ob,则将其ob.dep.id记录,防止死循环

scheduler

方法/类作用
queueWatcher(watcher: WatcherInstance)将watcher加入队列中,下个周期开始触发watcher.run
flushSchedulerQueue ()排序并触发watcher队列
let waiting = false;
let flushing = false;
let index = 0;
let has: { [key: number]: boolean } = {};
// 循环 watcher 的id记录
let circular: { [key: number]: number } = {}
export function queueWatcher(watcher: WatcherInstance) {}
//如果a,b两个watcher 互相影响,则会造成死循环,用circular计数,防止崩溃
function flushSchedulerQueue()

array

const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
// 
// 修改数组原生方法,当使用以上方法时,若果是插入数据则会触发ob.observeArray(inserted),然后 this.__ob__.dep.notify();以达到触发数组绑定的目的
methodsToPatch.forEach(function (method: string) {
})
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值