class Vue{
constructor(options){
const data=options.data;
this._data=data;
_proxy(this,'_data',data);
observer(this._data);
new Watch(this, function() {
return data.name + ' create defineReactive'
}, function() {
console.log('watch callback: ', this.value)
})
}
}
const _proxy=(vm,sourceKey,data)=>{
Object.keys(data).forEach(key=>{
Object.defineProperty(vm,key,{
get (){
return vm[sourceKey][key]
},
set(val){
vm[sourceKey][key]=val
}
})
})
}
const observer=(data)=>{
const ob=new Observer(data);
}
class Observer{
constructor(data){
this.walk(data);
}
walk(data){
Object.keys(data).forEach(key=>{
defineReactive(data,key);
})
}
}
const defineReactive=(data,key)=>{
let val=data[key];
const dep=new Dep();
Object.defineProperty(data,key,{
get(){
dep.depend();
return val;
},
set(nVal){
val=nVal;
dep.notfify();
}
})
}
class Dep{
constructor(){
this.uid=Dep.uid++;
this.subs=[];
}
static uid=0;
static target=null;
addSub(wather){
this.subs.push(wather);
}
depend(){
if(Dep.target){
Dep.target.addDep(this);
}
}
removeSub(wather){
const index=this.subs.indexOf(wather);
this.subs.splice(index,1)
}
notfify(){
this.subs.forEach(sub=>{
sub.update();
})
}
}
class Watch{
constructor(vm,render,cb){
this.vm=vm;
this.render=render;
cb=this.cb=cb;
this.deps=[];
this.depsIdSet=new Set();
this.newDeps=[];
this.newDepsIdSet=new Set();
this.update();
}
get(){
this.newDeps=[];
this.newDepsIdSet=new Set();
Dep.target=this;
const val= this.render();
Dep.target=null;
this.deps.forEach(oldDep=>{
const noInNewDep=!this.newDepsIdSet.has(oldDep.uid);
if(noInNewDep){
oldDep.removeSub(this);
}
})
this.deps=this.newDeps;
this.depsIdSet=this.newDepsIdSet;
return val
}
addDep(dep){
if(!this.newDepsIdSet.has(dep.uid)){
this.newDepsIdSet.add(dep.uid);
this.newDeps.push(dep);
if(!this.depsIdSet.has(dep.uid)){
dep.addSub(this);
}
}
}
update(){
this.value=this.get();
this.cb(this.value);
}
}
let student = new Vue({
data: {
name:'小明',
}
})
console
student.name = '小红'
console.log('log=>student',student);
setTimeout(()=>{
student.name = '小刚'
},1000)