3.Vue2响应式原理,对象属性劫持,深度属性劫持

1.在操作data的函数中调用observe方法,观察data中的数据是否有操作

import { observe } from "./observe/index"

//对用户传进来的选项进行操作
export function initState(vm) {
  const opts = vm.$options  //获取所有的选项
  if (opts.data) {
    initData(vm)
  }
}

//把data上的数据代理到vm身上,这样就可以通过this.xxx获取data中的数据,有个疑问就是这样会不会影响到性能?或者说真的有这个必要吗?通过this._data获取数据到底有什么不好的地方,暂时不清楚,学清楚了再来看吧
function proxy(vm, target, key) {
  Object.defineProperty(vm, key, {
    get() {
      return vm[target][key]
    },
    set(newValue) {
      if (newValue === vm[target][key]) return
      vm[target][key] = newValue
    }
  })
}

//对data中的数据进行操作
function initData(vm) {
  let data = vm.$options.data //data可能是函数或对象
  data = typeof data === 'function' ? data.call(this) : data
  // 对数据进行响应式的劫持
  vm._data = data
  observe(data) //给data中的每个属性都添加上get和set
  for (let key in data)
    proxy(vm, '_data', key) //将vm._data用vm代理
}

 2.在observe中对data中的属性进行劫持,遍历属性重新定义,有点消耗性能

//Observe/index.js
class Observer {
  constructor(data) {
    // Object.defineProperty只能劫持已经存在的数据(Vue2中单独写了一些api完成,例如 $set,$delete)
    this.walk(data)
  }
  walk(data) {
    // 重新定义属性,性能会差一些,Vue3改用了Proxy
    Object.keys(data).forEach(key => defineReactive(data, key, data[key]))
  }
}

//进行属性劫持的函数
export function defineReactive(target, key, value) {//闭包,value无法销毁,属性劫持
  observe(value)  //如果这个value还是一个对象的话,就对value再进行一次属性劫持
  Object.defineProperty(target, key, {
    // 此处的get并没有参数,我真是个小可爱,写了个value,导致之后读取的值全部都是undefined
    get() { //取值 执行get
      return value
    },
    set(newValue) { //赋值 执行set
      if (newValue === value) return
      observe(newValue)   //赋值的时候如果赋值的是一个对象,再次进行劫持
      value = newValue
    }
  })
}
export function observe(data) {
  if (typeof data !== 'object' || data === null) {
    // 只对对象进行劫持
    return
  }
  // 如果数据已经劫持过了,就不在劫持了(增添一个判断数据是否已被劫持的类)
  return new Observer(data)
}

你可能感兴趣的:(Vue源码学习,vue.js)