看vue源碼,梳理一下響應(yīng)式對(duì)象
輸入
const obj = {
a: {
num: 1,
text: '123'
},
b: {
num: 2
},
};
輸出
obj={
a: {
num: 1,
text: "123",
__ob__: Observer {value: {…}, dep: Dep},
get num: ? reactiveGetter(),
set num: ? reactivesetter(newVal),
get text: ? reactiveGetter(),
set text: ? reactivesetter(newVal),
__proto__: Object,
},
b:{
num: 2,
__ob__: Observer {value: {…}, dep: Dep},
get num: ? reactiveGetter(),
set num: ? reactivesetter(newVal),
__proto__:
},
__ob__: Observer {value: {…}, dep: Dep},
get a: ? reactiveGetter(),
set a: ? reactivesetter(newVal),
get b: ? reactiveGetter(),
set b: ? reactivesetter(newVal),
__proto__: Object,
}
實(shí)現(xiàn)
let uid = 0;
//保存訂閱者
class Dep {
constructor(){
this.id = uid++;
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
//發(fā)布通知
notify() {
let subs = this.subs.slice();
for (let i = 0; i < subs.length; i++) {
subs[i].update();
}
}
}
//給對(duì)象掛載__ob__: {value...,dep...}
function def(obj, key, val,enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
//給對(duì)象掛載get set
function defineReactive(obj, key, val) {
const dep = new Dep();
let property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return;
}
const getter = property && property.get;
const setter = property && property.set;
if ((!getter || setter)) {
val = obj[key];
}
let childOb = observer(val);
Object.defineProperty(obj,key,{
enumerable: true,
configurable: true,
get:function reactiveGetter() {
const value = getter ? getter.call(obj) : val;
return value;
},
set: function reactivesetter(newVal) {
const value = getter ? getter.call(obj) : val;
if (newVal === value) {
return
}
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = observer(newVal);
//觸發(fā)通知
obj.__ob__.dep.notify();
}
})
}
//深度遍歷對(duì)象里的值 把每個(gè)都變成響應(yīng)式
class Observer{
constructor(value) {
console.info(this);
this.value = value;
this.dep = new Dep();
def(value, '__ob__', this);
if (Array.isArray(value)) {
}else {
this.walk(value);
}
}
walk(obj){
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i]);
}
}
}
//把普通對(duì)象變成響應(yīng)式對(duì)象
function observer(value) {
if (typeof value !== 'object') {
return;
}
let ob;
ob = new Observer(value);
return ob;
}
const obj = {
a: {
num: 1,
text: '123'
},
b: {
num: 2
},
};
let up = {
update: () => {
console.log('update...');
}
};
observer(obj);
console.info(obj);
obj.__ob__.dep.addSub(up);
obj.a = 10;