Proxy 是 JavaScript 2015 的一個(gè)新特性。Proxy 的代理是針對整個(gè)對象的求类,而不是對象的某個(gè)屬性
嘹吨,因此不同于 Object.defineProperty 的必須遍歷對象每個(gè)屬性妖混,Proxy 只需要做一層代理就可以監(jiān)聽同級結(jié)構(gòu)下的所有屬性變化痹屹,當(dāng)然對于深層結(jié)構(gòu)章郁,遞歸還是需要進(jìn)行的。此外**Proxy支持代理數(shù)組的變化痢掠。
/* based on proxy */
// 使用 Proxy 時(shí)需要定義一個(gè)代理對象 handler 來對目標(biāo)進(jìn)行代理操作驱犹,
// 這個(gè)對象主要有兩個(gè)方法,即 get 和 set,
// 分別為 獲取和設(shè)置屬性值的時(shí)候觸發(fā)足画。同時(shí)在內(nèi)部的實(shí)現(xiàn)需要利用到 Reflect對象
//
//
// 首先明確 reactive 函數(shù)接收一個(gè)參數(shù)雄驹,
// 需要對這個(gè)參數(shù)進(jìn)行代理,并返回代理后的結(jié)果淹辞。
// 如果參數(shù)是對象才需要代理医舆,否則直接返回。
// 定義一個(gè)緩存對象
const toProxy = new WeakMap(); // 保存代理后的對象
/* 返回一個(gè)被代理后的結(jié)果象缀,通過操作這個(gè)結(jié)果可以來實(shí)現(xiàn)響應(yīng)式, 例如視圖更新 */
function reactive(target) {
// 如果是個(gè)對象蔬将,則返回被代理后的結(jié)果,如果不是則直接返回
if(!isObject(target)) {
return target;
}
if(toProxy.get(target)) { // 判斷對象是否已經(jīng)被代理了
return toProxy.get(target);
}
const handler = {
get(target, key, receiver) {
const proxyTarget = Reflect.get(target, key, receiver);
// 相當(dāng)于 return target[key]
if(isObject(target[key])) {
return reactive(proxyTarget);
}
return proxyTarget;
},
set(target, key, value, receiver) {
// 只對私有屬性的修改動(dòng)作觸發(fā)視圖更新
if(!target.hasOwnProperty(key)) {
trigger();
}
return Reflect.set(target, key, value, receiver);
// 相當(dāng)于 target[key] = value
}
};
// 利用 Proxy 來代理這個(gè)對象屬性
let observed = new Proxy(target, handler);
toProxy.set(target, observed); // 保存已代理的對象
return observed;
}
// 提示視圖需要更新
function trigger() {
console.log('視圖需要更新');
}
function isObject(param) {
return typeof param === 'object' && param !== null;
}