vue2源码学习(一)---手写监听对象

代码结构

  index.js----vue入口文件

  state.js----初始化data,并将其代理至vm实例

  observe.js----监听data内的对象

//index.js
import { initState } from './state' function Vue(options){ const vm = this; vm.$options = options; // 初始化状态 initState(vm); } export default Vue;
//state.js
import { observe } from './observe'

export function initState (vm) {
  const opts = vm.$options;
  if (opts.data) {
    initData(vm);
  }
}

function proxy (vm, target, key) {//通过代理将vm.xxx转发到vm._data.xxx
  Object.defineProperty(vm, key, {
    get () {
      return vm[target][key]
    },
    set(newV){
      vm[target][key] = newV
    }
  })
}

function initData (vm) {
  let data = vm.$options.data;//data可能是一个函数或者一个对象
  data = vm._data = typeof data === 'function' ? data.call(vm) : data;

  vm._data = data
//  对数据进行劫持 defineProperty
  observe(data);

//  将vm._data用vm来代理
  for (const key in data) {
    proxy(vm, '_data', key)
  }

}
//observe.js
class Observer{
  constructor (data) {
  //  Object.defineProperty只能劫持已经存在的属性(所以vue里定义了$set,$delete)
    this.walk(data)
  }
  walk(data){
    //重新定义属性
    Object.keys(data).forEach(key=> defineReactive(data,key,data[key]))
  }
}

export function defineReactive(target,key,value){//闭包
  observe(value) //对所有的对象进行属性劫持
  Object.defineProperty(target,key,{
    get(){//取值的时候会执行get
      return value
    },
    set(newV){//修改的时候会执行set
      if(newV===value)return
      observe(newV)//防止新值为对象,所以对新值进行再次代理
      value = newV
    }
  })
}

export function observe(data){
//  对data进行劫持
  if(typeof data!=='object'||data==null){
    return;//只对对象进行劫持
  }
//  如果一个对象被劫持过了,就不需要再劫持了(判断一个对象是否被接吃过,可以增添一个实例,用实例来判断)

  return new Observer(data)
}

 

posted @ 2022-06-30 22:14  cuteyuchen  阅读(112)  评论(0编辑  收藏  举报