前段时间看阮一峰老师的es6
入门向大家提了一点关于解构赋值的问题之后,有个学长说es6
最难懂的应该是Proxy
了,所以说有难度的东西就应该挑战着玩一下的说。
然后看了一下觉得怪有意思的。所谓的Proxy
,是一个用于修改某些操作的默认行为,原话是:
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
说实话,我并不是很能明白这段话说了什么。简单的学习来看,Proxy
给了我一种人如其名的感觉,以网络为原型的话相当于在目标主机与请求方之间建立了一个代理,然后可以肆意的操作两边来往的数据。又有点像laravel
的中间件,又有点像python
的装饰器。
一个简单的例子
let person = {
name: '咕咕咕',
age: 38
}
let proxy = new Proxy(person, {
get : (target, key) => {
if(key == 'age') {
return target[key] > 18 ? 18 : target[key];
}else{
return target[key];
}
}
})
console.log(proxy.age) //18
这里新建了一个Proxy
实例,定义了一个针对获取person
对象的属性的拦截行为,即get
一般而言,调用person对象的属性会这么写成这样:person.age
,其中的age
就是属性名,然后person
是对象,然后在Proxy
也就是代理内部的话就可以获取到这个对象以及调用属性名,就是target
和key
。
然后再调用proxy
的get
方法的时候实际上就执行了定义在Proxy
的get
方法。
写在Proxy内的方法的参数名字并不重要,顺序即可似乎。
Proxy支持的拦截操作似乎较多,但是很多都是目前的我不甚熟悉的,所以只做摘录(x
get(target, propKey, receiver)
:拦截对象属性的读取,比如proxy.foo
和proxy['foo']
。set(target, propKey, value, receiver)
:拦截对象属性的设置,比如proxy.foo = v
或proxy['foo'] = v
,返回一个布尔值。has(target, propKey)
:拦截propKey in proxy
的操作,返回一个布尔值。deleteProperty(target, propKey)
:拦截delete proxy[propKey]
的操作,返回一个布尔值。ownKeys(target)
:拦截Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()
的返回结果仅包括目标对象自身的可遍历属性。getOwnPropertyDescriptor(target, propKey)
:拦截Object.getOwnPropertyDescriptor(proxy, propKey)
,返回属性的描述对象。defineProperty(target, propKey, propDesc)
:拦截Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。preventExtensions(target)
:拦截Object.preventExtensions(proxy)
,返回一个布尔值。getPrototypeOf(target)
:拦截Object.getPrototypeOf(proxy)
,返回一个对象。isExtensible(target)
:拦截Object.isExtensible(proxy)
,返回一个布尔值。setPrototypeOf(target, proto)
:拦截Object.setPrototypeOf(proxy, proto)
,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。apply(target, object, args)
:拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。construct(target, args)
:拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)
。
对于get
方法而言,允许传入的三个参数分别是target
,key
,receiver
,分别代表着
- 代理的目标
- 获取的参数
- 读操作所在对象(一般就是
proxy
的实例)
然后有些注意事项就是即使在proxy
内也不能修改来自target
的read-only and non-configurable
,至于为什么要有这个规则不是很符合我的理解。这不符合一个作为中间件或者代理服务器的行为,说明我对他的理解出现了一些偏差。
比如这个
let x = Object.defineProperties({},{
age : {
value : 19,
writable : false,
configurable: false
},
name : {
value : "咕咕咕",
writable : false,
configurable: false
},
})
let proxy = new Proxy(x,{
get: (t,k) => 18
})
console.log(proxy.age)
这样的代码当x
的age
确实是18
的时候,可以正常返回18
。
但是当x.age
不是18的时候则会遇到报错:
TypeError: 'get' on proxy: property 'age' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '19' but got '18')
让人感到有些困惑。