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) }