Vue 2以DefineProperty
攔截數據達到監聽效果。(可以數據監聽的DefineProperty與Vue2-D05)
Vu3 Composition API的底層,改以Proxy
監聽數據和物件,
昨天先聊了常和Proxy
搭配的Refelct
今天殺入正題,看看Proxy到底怎麼用?
哪裡好?
到底為什麼要從DefineProperty
改成Proxy
Proxy 英文就是代理的意思,JS 的Proxy出現於ES6,可以代理物件,
來攔截或重新定義基本操作。
環遊非洲第07天:非洲101 之Q
非洲哪個國家使用手機支付比例奪冠?高達八成網際網路使用人口都在用!
A.肯亞
B.南非
C.奈及利亞
D.埃及
Proxy是建構函數,傳進去的參數主要就是:
1.target 目標對象
2.handler 事件處理器決定你要攔截什麼或是要重新定義什麼 (要用物件來包喔)
handler裡面常用的方法也跟Object
很像,如set
和get
...
下面就以set
為例子,看Proxy如何和defineProperty
一樣做到攔截
const myCountry = {name: 'Kenya'}
const handler = {
get(){
console.log('被讀取了');
return myCountry.name
}
}
const proxyCountry = new Proxy(myCountry,handler);
//當我們要讀取name這個屬性時,就可以攔截到,回傳我們設定的console.log
console.log(proxyCountry.name); //return '被讀取了', Kenya
Reflect对象经常和Proxy代理一起使用,原因有3:
1.Reflect的方法和Proxy第2個handle參數方法是一樣的。
2.Proxy get/set()方法需要的返回值正是Reflect的get/set方法的返回值,可以配合使用
3.Proxy和Reflect都有receiver參數,可以正確綁定this指向-->重要!!
4.操作目標報錯時返回 false
引用&修改自:Proxy是代理,Reflect是干嘛用的?
來看看兩個搭配如何做到攔截!
MDN說Proxy的get是一個陷阱(trap)(好可愛的說法,還是其實有別的翻譯XD)
可以攔截以下方法:
原物件上的屬性讀取
讀取原型鍊上的屬性 Inherited property access: Object.create(proxy)[foo]
Reflex.get
參數跟Reflec的一樣,get(target, property, receiver)
來看看用跟不用Reflect會怎麼樣:
const parentCountry = {
name: 'Kenya',
get value() {
return this.name;
},
};
const handler = {
get(target, key, receiver) {
//相當於targetp[key]
return Reflect.get(target, key);
// return Reflect.get(target, key, receiver);
},
};
const proxy = new Proxy(parentCountry, handler);
const childCapital = {
name: 'Nairobi',
};
// 設置childCapital繼承parentCountry代理對象proxy
Object.setPrototypeOf(childCapital, proxy);
console.log(childCapital.value);
猜猜Console.log出來的是什麼?
Kenya
我們的this
指向在proxy的get陷阱中被重新指向了
這時候就要靠receiver
上場啦,它可以幫我們把this
指回繼承對象本身
const parentCountry = {
name: 'Kenya',
get value() {
return this.name;
},
};
const handler = {
get(target, key, receiver) {
//類似於targetp[key].call(receiver)
return Reflect.get(target, key, receiver);
},
};
const proxy = new Proxy(parentCountry, handler);
const childCapital = {
name: 'Nairobi',
};
// 設置childCapital繼承parentCountry代理對象proxy
Object.setPrototypeOf(childCapital, proxy);
console.log(childCapital.value); //Nairobi
案例引用修改自:为什么Proxy一定要配合Reflect使用?
詳細也請去上面看看~
回頭看一下defineProperty
做不到的事情:
1.有多Key-->要遍歷所有對象,很麻煩
2.Object的刪除和新增屬性-->無法監聽
3.Array添加數據或是移除(push & shift)-->無法監聽
來用Proxy實作,封裝一個reactive
試試看
function reactive(obj) {
const proxy = new Proxy(obj, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
console.log(`攔截! ${key}:${res}`)
return res
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver)
console.log(`設置! ${key}:${value}`)
return res
},
deleteProperty(target, key) {
const res = Reflect.deleteProperty(target, key)
console.log(`刪除! ${key}:${res}`)
return res
}
})
return proxy
}
來測試一下:
const myCountry = reactive({
name: 'Kenya'
})
// 設置不存在的屬性
myCountry.capital = 'Nairobi' // success && console: 設置! capital:Nairobi
// 删除属性
delete myCountry.capital // success && console: true
const africa = ['Nigeria','South Africa','Kenya']
const proxyAfrica = reactive(africa)
proxyAfrica.push('Egypt')
// console: 攔截! push:function push() { [native code] }
//攔截! length:3
//設置! 3:Egypt
//設置! length:4
案例引用修改自:Vue3.0里为什么要用 Proxy API 替代 defineProperty API ?
就是簡易版的Vue Proxy API 介紹,
開始來玩Vue3 Reactive API囉!
環遊非洲第07天:非洲101 之A
答案是~~肯亞!
網路使用者的八成都在使用手機支付,比例甚至高過歐洲。
非洲最大的手機支付APP-M-Pesa就來自肯亞,
他們稱每個月在非洲就有5000萬的活躍用戶。其實手機支付可以成長這麼快的一個原因是,
大部分的人都沒有銀行帳號。(經濟弱勢的人很難申請銀行帳號)
來源:Mobile payment in Africa is more popular than you may think - here's why