代码结构
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)
}