proxy是ES6,新增的一个“拦截器”,也能够理解成是ES6,新增的一种元变编程功能。es6
proxy用于修改某些操做的默认行为,等同于在语言层面做出修改。web
let proxy = new Proxy({},{
get:function(target,property){
return 35
}
})
proxy.xxx //35
复制代码
「Proxy构造函数的解释」编程
Proxy构造函数接受两个参数,第一个参数是所要代理的目标对象;第二个参数是一个配置对象,对于每个被代理的操做,须要提供一个对应的处理函数,该函数将拦截对应的操做。数组
拦截对象属性的读取,target是被代理的对象,propKey是须要拦截的键,receiver是一个可选的参数。app
🌰编辑器
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
get: function (target, key) {
console.log(target, key)
return target[key]
}
})
console.log(proxy.name)
复制代码
拦截对象属性的设置,target是被代理的对象,propKey是须要拦截的键,value是要设置的值,receiver是一个可选的参数。函数
🌰ui
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
set: function (target, key, value) {
return target[key] = value
}
})
proxy.name = 'yuefengsu'
console.log(proxy.name)
复制代码
拦截propKey in target的操做,返回一个布尔值。this
🌰spa
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
has:function(target,key){
console.log(target,key)
return key in target
}
})
console.log('name' in proxy)
复制代码
❝若是原对象不可配置或者禁止扩展,那么这是has拦截会报错;还有has方法拦截的是HasProperty,而不是HasOwnProperty,因此has方法不判断一个属性是对象自身仍是继承的属性。
❞
拦截 delete target[propKey]的操做,返回一个布尔值。
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
deleteProperty: function (target, key) {
console.log(target, key)
if(!(key in target)) throw TypeError('不存在的key')
return delete [target, key]
}
})
console.log(delete proxy['name'])
复制代码
❝目标对象自身的不可配置的属性不能被deleteProperty方法删除,不然会报错。
❞
拦截Object.getOwnPropertyNames(proxy),Object.getOwnPropertySymbols(proxy),Object.keys(proxy),返回一个数组,该方法返回目标对象因此自身属性的属性名。
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
ownKeys:function(target){
console.log(target)
return ['name']
}
})
console.log(Object.keys(proxy))
复制代码
❝ownKeys方法返回的数组成员只能是字符串或者Symbol值,若是是其余类型的值,或者返回的根本不是数组,就会报错;若是目标对象自身包含不可配置的属性,则该属性必须ownKeys方法返回,不然也会报错;若是目标对象是不可扩展的,这时ownKeys方法返回的数组中必须包含原对象的因此属性,且不能包含多余的属性,不然也会报错。
❞
拦截Object.getOwnPropertyDescriptor(proxy,propKey),返回属性的描述对象。
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
getOwnPropertyDescriptor:function(target,key){
console.log(target,key)
return Object.getOwnPropertyDescriptor(target,key)
}
})
console.log(Object.getOwnPropertyDescriptor(obj,'name'))
复制代码
拦截Object.defineProperty(proxy,propKey,propDesc),Object.defineProperties(proxy,propDesc),返回一个布尔值。
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
defineProperty:function(target,key,desc){
console.log(target,key,desc)
return true
}
})
console.log(Object.defineProperty(proxy,'name',{}))
复制代码
❝若是目标对象不可扩展,则defineProperty不能增长目标对象中不存在的属性,不然会报错,另外,若是目标对象的某个属性不可写或者不可配置,则defineProperty方法不得改变这两个设置。
❞
拦截Object.preventExtensions(proxy),返回一个布尔值。
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
preventExtensions:function(target){
console.log(target)
Object.preventExtensions(target)
return true
}
})
console.log(Object.preventExtensions(proxy))
复制代码
❝这个方法有一个限制,只有目标对象不可扩展(既Obeject.preventExtensions(proxy)为false)proxy.preventExtensions才能返回true,不然会报错。
❞
拦截Object.getPrototypeOf(proxy),返回一个对象。具体拦截以下👇
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
getPrototypeOf:function(target){
console.log(target)
return obj
}
})
console.log(Object.getPrototypeOf(proxy))
复制代码
❝getPrototypeOf方法的返回值必须是对象或者是null,不然会报错。另外,若是目标对象不可扩展,getPrototypeOf方法必须返回目标对象的原型对象。
❞
拦截Object.isExtensible(proxy),返回一个布尔值。
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
isExtensible:function(target){
console.log(target)
return true
}
})
console.log(Object.isExtensible(proxy))
复制代码
❝该方法只能返回布尔值,不然返回的值会被自动转为布尔值。
❞
拦截Object.setPrototypeOf(proxy,proto),返回一个布尔值。
let obj = {
name: "yuefeng"
}
let proxy = new Proxy(obj, {
setPrototypeOf:function(target,proto){
console.log(target,proto)
target.prototype = proto
return true
}
})
console.log(Object.setPrototypeOf(proxy,obj))
复制代码
❝该方法只能返回布尔值,不然会被自动转为布尔值。另外,若是目标对象不可扩展,setPrototypeOf方法不得改变目标对象的原型。
❞
拦截Proxy实例,并将其做为函数调用的操做,好比proxy(...args)、proxy.call(object,...args)、proxy.apply(object,...args)。
let proxy = new Proxy(Person, {
apply:function(target,ctx,args){
console.log(target,ctx,args)
return 'i am a boy'
}
})
function Person (){
return 'i am a gril'
}
console.log(proxy())
复制代码
拦截Proxy实例做为构造函数调用的操做,好比new proxy(...args)。
let proxy = new Proxy(Person, {
construct:function(target,args){
console.log(target,args)
return {value:'18'}
}
})
function Person (){
return 'i am a gril'
}
console.log(new proxy().value)
复制代码
❝construct方法必须返回一个对象,不然会报错。
❞
let proxy = new Proxy({}, {
get: function (target, key) {
console.log(target, key)
return target[key]
},
set: function (target, key, value) {
return target[key] = value
},
has: function (target, key) {
console.log(target, key)
return key in target
},
deleteProperty: function (target, key) {
console.log(target, key)
if(!(key in target)) throw TypeError('不存在的key')
return delete [target, key]
},
ownKeys:function(target){
console.log(target)
return ['name']
},
getOwnPropertyDescriptor:function(target,key){
console.log(target,key)
return Object.getOwnPropertyDescriptor(target,key)
},
defineProperty:function(target,key,desc){
console.log(target,key,desc)
return true
},
preventExtensions:function(target){
console.log(target)
Object.preventExtensions(target)
return true
},
getPrototypeOf:function(target){
console.log(target)
return obj
},
isExtensible:function(target){
console.log(target)
return true
},
setPrototypeOf:function(target,proto){
console.log(target,proto)
target.prototype = proto
return true
},
apply:function(target,ctx,args){
console.log(target,ctx,args)
return 'i am a boy'
},
construct:function(target,args){
console.log(target,args)
return {value:'18'}
}
})
复制代码
「Proxy能够代理针对目标对象的访问,但它不是目标对象的透明代理,既不作任何拦截的状况下也没法保证于目标对象的行为一致。主要缘由就是Proxy代理的状况下,目标对象内部的this关键字会指向Proxy代理」
🌰
const target ={
m:function(){
console.log(this === proxy)
}
}
const proxy = new Proxy({},{})
target.m() // false
proxy.m() // true
复制代码
参考资料