ES6之Proxy的get方法詳解
Proxy是在ES2015(ES6)中新添加內(nèi)置對象,用于自定義一些基本操作。
這篇文章是我在學(xué)習(xí)Proxy的時(shí)候?qū)τ趃et方法的一些心得。
作為ES2015新定義的內(nèi)置對象,Proxy 能夠攔截并且自定義對象以及函數(shù)的一些基本操作,具有很高的優(yōu)先級和便利性,能夠讓我們在寫代碼的時(shí)候多出一種解決難題的途徑。
Proxy的get方法用于攔截對象屬性的讀取操作,例如 obj.key 和 obj.[key]。在給Proxy的handler參數(shù)中設(shè)置get方法后,每當(dāng)進(jìn)行讀取操作時(shí),會優(yōu)先調(diào)用該get方法,我們可以在這個(gè)方法函數(shù)中對讀取行為進(jìn)行攔截。請看下面的代碼:
const obj = { key: 1 } const proxy = new Proxy(obj, { get: function(target, property, receiver) { console.log('get', property) return target[property] } }) console.log(proxy.key) // get key // 1
get方法的參數(shù)一共有三個(gè):target是實(shí)例化Proxy時(shí)使用的對象,在這個(gè)例子中是obj;而property是這次讀取操作中想要獲取的屬性名,在這個(gè)例子中是key;最后一個(gè)參數(shù)receiver則是這個(gè)實(shí)例化的Proxy自身,即proxy。
在這個(gè)例子中,我在get方法的最后返回了target[property],這是為了能夠讓讀取操作能夠進(jìn)行下去。由于Proxy的get方法是最先被調(diào)用的,所以這里返回的內(nèi)容就是我們讀取操作能夠獲得的結(jié)果;如果我們在這里不返回任何值,那么就會得到undefined。
receiver和死循環(huán)
要注意的是,千萬不要在get方法中讀取receiver的屬性,因?yàn)閞eceiver實(shí)質(zhì)上就是proxy自身,所以receiver.key這句代碼就等同于proxy.key,會重新調(diào)用get方法導(dǎo)致死循環(huán)。
const obj = { key: 1 } const proxy = new Proxy(obj, { get: function(target, property, receiver) { console.log(receiver.key) return target[property] } }) console.log(proxy.key) // 死循環(huán)!
原型鏈上的getter
有時(shí)候,我們會在對象之中使用getter和setter來定制屬性的賦值和讀取。在這時(shí),如果proxy的get方法內(nèi)部有使用到target[property]的話,target[property]的值會受到目標(biāo)對象的getter的影響。因此調(diào)用get方法的時(shí)候請注意在目標(biāo)對象中是否有用到getter。
const obj = { get key() { return 'string' }, set key(value) { console.log(`key is ${value}, it is a ${typeof value}`) } } const proxy = new Proxy(obj, { get: function(target, property, receiver) { if(typeof target[property] !== 'string') { return target[property] } else { throw new TypeError(`The type of ${property} is String!`) } } }) proxy.key = 100 console.log(proxy, obj) // key is 100, it is a number // The type of key is String!
在上方的例子中,如果訪問obj的非數(shù)字類型的屬性,就會拋出一個(gè)錯誤,但是由于obj中g(shù)etter的原因,無論我給key屬性賦什么值,在訪問key屬性的時(shí)候肯定會拋出錯誤。
如果僅僅要注意目標(biāo)對象中的getter還算容易的,但是如果目標(biāo)對象繼承自其他對象,那么事情就變得有些麻煩了,請看下面的例子:
const parentObj = { get key() { return 'string' }, set key(value) { console.log(`key is ${value}, it is a ${typeof value}`) } } const obj = Object.create(parentObj) const proxy = new Proxy(obj, { get: function (target, property, receiver) { if (typeof target[property] !== 'string') { return target[property] } else { throw new TypeError(`The type of ${property} is String!`) } } }) proxy.key = 100 console.log(proxy.key) // key is 100, it is a number // The type of key is String!
如代碼所示,目標(biāo)對象obj繼承自parentObj,而parentObj中使用了getter方法,那么使用proxy的get方法仍舊會報(bào)錯。實(shí)際運(yùn)用中原型鏈可能會很長,getter可能會存在于原型鏈的任何一個(gè)地方中,所以在使用Proxy的get方法時(shí)請一定要注意。
但是如果把parentObj上的key遮蔽掉,就不會發(fā)生拋出錯誤的情況了。比如在創(chuàng)建obj的時(shí)候申明的key,代碼如下:
const parentObj = { get key() { return 'string' }, set key(value) { console.log(`key is ${value}, it is a ${typeof value}`) } } const obj = Object.create(parentObj, { key: { value: null, writable: true } }) const proxy = new Proxy(obj, { get: function (target, property, receiver) { if (typeof target[property] !== 'string') { return target[property] } else { throw new TypeError(`The type of ${property} is String!`) } } }) proxy.key = 100 console.log(proxy.key) // 100
同樣的,我們也可以使用Object.defineProperty()和Object.assign()這兩個(gè)方法來達(dá)到相同的目的:
Object.defineProperty(obj, 'key', { value: null, writable: true }) obj = Object.assign({}, obj, { key: null })
但是要注意使用Object.assign()的時(shí)候不能這么些:
obj = Object.assign(obj, { key: null })
這樣寫法無法遮蔽掉parentObj上的key屬性,使用的時(shí)候仍舊會拋出錯誤。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
學(xué)習(xí)JavaScript設(shè)計(jì)模式(封裝)
這篇文章主要帶領(lǐng)大家學(xué)習(xí)JavaScript設(shè)計(jì)模式,其中重點(diǎn)介紹封裝,舉例說明封裝的思想,對封裝進(jìn)行詳細(xì)剖析,感興趣的小伙伴們可以參考一下2015-11-11編寫跨瀏覽器的javascript代碼必備[js多瀏覽器兼容寫法]
下面比較了幾種瀏覽器之間的差異,在寫javascript代碼時(shí) 要時(shí)刻注意這些差異2008-10-10JavaScript高級程序設(shè)計(jì) 讀書筆記之十 本地對象Date日期
本地對象Date日期操作實(shí)現(xiàn)方法,需要的朋友可以參考下2012-02-02JavaScript 讀URL參數(shù)增強(qiáng)改進(jìn)版版
網(wǎng)上有不少JavaScript 讀 URL 參數(shù)的函數(shù),但沒考慮到 URL 中帶 # 符的情況,我的可以處理這種情況,并使用了點(diǎn)對象寫法,優(yōu)化了些性能。2008-10-10JavaScript實(shí)現(xiàn)輸入框(密碼框)出現(xiàn)提示語
有時(shí)候我們需要在登陸表單有一些提示語言,比如“請輸入用戶名”和“請輸入密碼”等語言,通過本文給大家介紹JavaScript實(shí)現(xiàn)輸入框(密碼框)出現(xiàn)提示語的相關(guān)知識,對js實(shí)現(xiàn)輸入框提示相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧2016-01-01