computed watch原理理解

本文详细探讨了Vue实例化过程中的数据劫持和初步渲染,讲解了Dep Watcher如何在数据变化时更新视图。接着,介绍了Computed的缓存机制,解释了在初始化渲染和后续数据变更时如何执行计算属性。最后,分析了Watch的工作原理,包括深检测、立即执行以及在数据变更时如何触发回调以更新视图。
摘要由CSDN通过智能技术生成
一、new Vue()的执行过程
1.1 数据劫持和初步渲染
function Vue (options) {
   
  // 初始化
  this._init(options)
  // 执行render函数
  this.$mount()
}
Vue.prototype._init = function (options) {
   
  const vm = this
  // 把options挂载到this上
  vm.$options = options
  if (options.data) {
   
    // 数据响应式
    initState(vm)
  }
  if (options.computed) {
   
    // 初始化计算属性
    initComputed(vm)
  }
  if (options.watch) {
   
    // 初始化watch
    initWatch(vm)
  }
}

initState()中实现数据劫持和代理:

function initState(vm) {
   
  // 拿到配置的data属性值
  let data = vm.$options.data;
  // 判断data 是函数还是别的类型
  data = vm._data = typeof data === 'function' ? data.call(vm, vm) : data || {
   };
  // 数据代理
  const keys = Object.keys(data);
  let i = keys.length;
  while(i--) {
   
    // 从this上读取的数据全部拦截到this._data到里面读取
    // 例如 this.name 等同于  this._data.name
    proxy(vm, '_data', keys[i]);
  }
  // 数据观察
  observe(data);
}

// 数据观察函数
function observe(data) {
   
  if (typeof data !== 'object' && data != null) {
   
    return;
  }
  return new Observer(data)
}

// 从this上读取的数据全部拦截到this._data到里面读取
// 例如 this.name 等同于  this._data.name
function proxy(vm, source, key) {
   
  Object.defineProperty(vm, key, {
   
    get() {
   
      return vm[source][key] // this.name 等同于  this._data.name
    },
    set(newValue) {
   
      return vm[source][key] = newValue
    }
  })
}

class Observer{
   
  constructor(value) {
   
    // 给每一个属性都设置get set
    this.walk(value)
  }
  walk(data) {
   
    let keys = Object.keys(data);
    for (let i = 0, len = keys.length; i < len; i++) {
   
      let key = keys[i]
      let value = data[key]
      // 给对象设置get set
      defineReactive(data, key, value)
    }
  }
}

function defineReactive(data, key, value) {
   
  Object.defineProperty(data, key, {
   
    get() {
   
      return value
    },
    set(newValue) {
   
      if (newValue == value) return
      observe(newValue) // 给新的值设置响应式
      value = newValue
    }
  })
  // 递归给数据设置get set
  observe(value);
}

initComputed()以及initWatch()后面再实现,这时候new Vue()中的this._init(options)执行完成,接着执行this.$mount()

// 挂载方法
Vue.prototype.$mount = function () {
   
  const vm = this
  new Watcher(vm, vm.$options.render, () => {
   }, true)  // 这里的参数true表示是渲染Watcher
}

在这里可以看到new了一个Watcher,此处的Watcher就是渲染Watcher,先看看Watcher的初步实现:

let wid = 0
class Watcher {
   
  constructor(vm, exprOrFn, cb, options) {
   
    this.vm = vm // 把vm挂载到当前的this上
    if (typeof exprOrFn === 'function') {
   
      this.getter = exprOrFn // 把exprOrFn挂载到当前的this上,这里exprOrFn 等于 vm.$options.render
    }
    this.cb = cb // 把cb挂载到当前的this上
    this.options = options // 把options挂载到当前的this上
    this.id = wid++  // 每个Watcher都有其id
    this.value = this.get() // 相当于运行 vm.$options.render()
  }
  get() {
   
    const vm = this.vm
    let value = this.getter.call(vm, vm) // 把this指向到vm,此时的getter即是render函数
    return value
  }
}

可以看到,当在this.$mount()new Watcher()渲染Watcher)时,会立刻执行this.get()方法去获取数据渲染,至此,首页渲染就完成了

1.2 Dep Watcher

在首页渲染的过程中,是data订阅的时期,以实现数据修改时能够修改视图

  • Dep类的实现:
// 依赖收集
let dId = 0
class Dep{
   
  constructor() {
   
    this.id = dId++ 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值