先看個(gè)題目
讓下列表達(dá)式成立
a === 1 && a === 2 && a === 3
我大致的思路是定義變量a = 0 每次取a得值時(shí)瓮具,先 a++蜈项,再返回。
ok要在完成取值之前攔截一步皿桑,并且輸出我們想要的值,就需要用的es5中的數(shù)據(jù)劫持了蔬啡。
于是我咔咔寫(xiě)出了下面的代碼:
window['a'] = 0;
Object.defineProperty(window,'a',{
get() {
window['a']++
return window['a']
}
})
然后就咔咔的報(bào)錯(cuò)了诲侮,報(bào)錯(cuò)原因是堆棧溢出。
我思考了一下箱蟆,原來(lái)如此沟绪,當(dāng)我取a的值時(shí),get劫持了我的操作空猜,此時(shí)我使a++,相當(dāng)于又取了a的值绽慈,又重復(fù)劫持了一次,所以死循環(huán)了辈毯。
所以我想我換一個(gè)不被劫持的值不得了坝疼,于是我咔咔寫(xiě)下了下面的代碼:
let count = 0;
Object.defineProperty(window,'a',{
get() {
count++;
return count;
}
})
結(jié)果果然沒(méi)錯(cuò)。
上面兩端代碼中谆沃,都用到了Object.defineProperty裙士。
官方解釋?zhuān)篛bject.defineProperty() 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性管毙, 并返回這個(gè)對(duì)象。
它可以定義一個(gè)新屬性桌硫,比如我上面的a夭咬,本來(lái)是不存在,卻被程序定義出來(lái)了铆隘。
或者修改一個(gè)現(xiàn)有的屬性卓舵,比如第一段程序中的window['a'],本來(lái)就有膀钠。
OK掏湾,據(jù)說(shuō)Vue2.x中的數(shù)據(jù)雙向綁定就用到了這個(gè)玩意。
如果想深入了解數(shù)據(jù)雙向綁定的實(shí)現(xiàn)肿嘲,請(qǐng)看文章:http://www.cnblogs.com/libin-1/p/6893712.html
接著說(shuō)Proxy
Proxy表面上和defineProperty差不多融击,后者能實(shí)現(xiàn)的,前者也能實(shí)現(xiàn)雳窟,比如監(jiān)聽(tīng)對(duì)象內(nèi)一個(gè)屬性的變化
let obj = new Proxy({a:1},{
get(target, p, receiver) {
console.log('取值')
},
set(target, p, value, receiver) {
console.log('改值')
}
})
相比defineProperty尊浪,Proxy具有下面幾個(gè)優(yōu)勢(shì)
- 監(jiān)聽(tīng)對(duì)象內(nèi)所有屬性時(shí),不需要遍歷,而defineProperty則需要遍歷拇涤。
- 支持?jǐn)?shù)組
- 不需要對(duì) keys 進(jìn)行遍歷捣作。這解決Object.defineProperty() 的第二個(gè)問(wèn)題.Proxy 是針對(duì)整個(gè) obj 的。所以 obj 內(nèi)部包含的所有的 key 鹅士,都可以走進(jìn) set券躁。(省了一個(gè) Object.keys() 的遍歷)
關(guān)于Proxy支持的攔截方法可參考官方文檔:
http://es6.ruanyifeng.com/#docs/proxy#Proxy-%E5%AE%9E%E4%BE%8B%E7%9A%84%E6%96%B9%E6%B3%95
Reflect對(duì)象
還是剛才的代碼
let obj = new Proxy({a:1},{
get(target, p, receiver) {
console.log('取值')
}
})
let a = obj.a
我咔咔的就輸出了a,結(jié)果卻是undefined,為啥掉盅,因?yàn)間et方法里只是攔截和監(jiān)聽(tīng)也拜,但是方法卻沒(méi)有返回。
我按照官方教程輸出了返回值怔接,代碼如下:
let obj = new Proxy({a:1},{
get(target, p, receiver) {
return Reflect.get(target,p,receiver)
}
})
let a = obj.a
取到了obj.a的值搪泳。
所以啥是Reflect?
官方解釋?zhuān)簽椴僮鲗?duì)象而提供的新API
http://es6.ruanyifeng.com/#docs/reflect
Reflect的優(yōu)勢(shì)
1.將Object對(duì)象的屬于語(yǔ)言?xún)?nèi)部的方法放到Reflect對(duì)象上,即從Reflect對(duì)象上拿Object對(duì)象內(nèi)部方法扼脐。
let obj = {a:1};
// old
Object.defineProperty();
// new
Reflect.deleteProperty()
- 將用 老Object方法 報(bào)錯(cuò)的情況岸军,改為返回false
// old
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
}
// new
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
- 讓Object操作變成函數(shù)行為
// old
'name' in Object
// new
Reflect.has(Object,'name')
- 在Proxy上有的方法,在Reflect就一定有瓦侮。在Proxy修改了默認(rèn)行為后艰赞,可通過(guò)Reflect保證默認(rèn)行為正常運(yùn)行。
let obj = new Proxy({a:1},{
get(target, p, receiver) {
// 改變默認(rèn)行文
console.log('取值')
// 使默認(rèn)行為正常執(zhí)行
return Reflect.get(target,p,receiver)
}
})
let a = obj.a
console.log(a) // 1
Reflect對(duì)象擁有的方法:
請(qǐng)參考官方文檔:http://es6.ruanyifeng.com/#docs/reflect