ES6之Proxy的get方法详解
Proxy是在ES2015(ES6)中新添加内置对象,用于自定义一些基本操作。
这篇文章是我在学习Proxy的时候对于get方法的一些心得。
作为ES2015新定义的内置对象,Proxy能够拦截并且自定义对象以及函数的一些基本操作,具有很高的优先级和便利性,能够让我们在写代码的时候多出一种解决难题的途径。
Proxy的get方法用于拦截对象属性的读取操作,例如obj.key和obj.[key]。在给Proxy的handler参数中设置get方法后,每当进行读取操作时,会优先调用该get方法,我们可以在这个方法函数中对读取行为进行拦截。请看下面的代码:
constobj={key:1} constproxy=newProxy(obj,{ get:function(target,property,receiver){ console.log('get',property) returntarget[property] } }) console.log(proxy.key) //getkey //1
get方法的参数一共有三个:target是实例化Proxy时使用的对象,在这个例子中是obj;而property是这次读取操作中想要获取的属性名,在这个例子中是key;最后一个参数receiver则是这个实例化的Proxy自身,即proxy。
在这个例子中,我在get方法的最后返回了target[property],这是为了能够让读取操作能够进行下去。由于Proxy的get方法是最先被调用的,所以这里返回的内容就是我们读取操作能够获得的结果;如果我们在这里不返回任何值,那么就会得到undefined。
receiver和死循环
要注意的是,千万不要在get方法中读取receiver的属性,因为receiver实质上就是proxy自身,所以receiver.key这句代码就等同于proxy.key,会重新调用get方法导致死循环。
constobj={key:1} constproxy=newProxy(obj,{ get:function(target,property,receiver){ console.log(receiver.key) returntarget[property] } }) console.log(proxy.key) //死循环!
原型链上的getter
有时候,我们会在对象之中使用getter和setter来定制属性的赋值和读取。在这时,如果proxy的get方法内部有使用到target[property]的话,target[property]的值会受到目标对象的getter的影响。因此调用get方法的时候请注意在目标对象中是否有用到getter。
constobj={ getkey(){ return'string' }, setkey(value){ console.log(`keyis${value},itisa${typeofvalue}`) } } constproxy=newProxy(obj,{ get:function(target,property,receiver){ if(typeoftarget[property]!=='string'){ returntarget[property] }else{ thrownewTypeError(`Thetypeof${property}isString!`) } } }) proxy.key=100 console.log(proxy,obj) //keyis100,itisanumber //ThetypeofkeyisString!
在上方的例子中,如果访问obj的非数字类型的属性,就会抛出一个错误,但是由于obj中getter的原因,无论我给key属性赋什么值,在访问key属性的时候肯定会抛出错误。
如果仅仅要注意目标对象中的getter还算容易的,但是如果目标对象继承自其他对象,那么事情就变得有些麻烦了,请看下面的例子:
constparentObj={ getkey(){ return'string' }, setkey(value){ console.log(`keyis${value},itisa${typeofvalue}`) } } constobj=Object.create(parentObj) constproxy=newProxy(obj,{ get:function(target,property,receiver){ if(typeoftarget[property]!=='string'){ returntarget[property] }else{ thrownewTypeError(`Thetypeof${property}isString!`) } } }) proxy.key=100 console.log(proxy.key) //keyis100,itisanumber //ThetypeofkeyisString!
如代码所示,目标对象obj继承自parentObj,而parentObj中使用了getter方法,那么使用proxy的get方法仍旧会报错。实际运用中原型链可能会很长,getter可能会存在于原型链的任何一个地方中,所以在使用Proxy的get方法时请一定要注意。
但是如果把parentObj上的key遮蔽掉,就不会发生抛出错误的情况了。比如在创建obj的时候申明的key,代码如下:
constparentObj={ getkey(){ return'string' }, setkey(value){ console.log(`keyis${value},itisa${typeofvalue}`) } } constobj=Object.create(parentObj,{ key:{ value:null, writable:true } }) constproxy=newProxy(obj,{ get:function(target,property,receiver){ if(typeoftarget[property]!=='string'){ returntarget[property] }else{ thrownewTypeError(`Thetypeof${property}isString!`) } } }) proxy.key=100 console.log(proxy.key) //100
同样的,我们也可以使用Object.defineProperty()和Object.assign()这两个方法来达到相同的目的:
Object.defineProperty(obj,'key',{ value:null, writable:true }) obj=Object.assign({},obj,{key:null})
但是要注意使用Object.assign()的时候不能这么些:
obj=Object.assign(obj,{key:null})
这样写法无法遮蔽掉parentObj上的key属性,使用的时候仍旧会抛出错误。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。