创建一个简单的Proxy
let target = {} let proxy = new Proxy(target, {}) proxy.name = 'proxy' console.log(proxy.name) // proxy console.log(target.name) // proxy target.name = 'target' console.log(proxy.name) // target console.log(target.name) // target
这个实例将proxy赋值给proxy.name属性时会在目标上创建name,代理只是简单的将操作转发给目标,他不会储存这个属性。相当于proxy.name和target.name引用的都是target.name的值。
使用set陷阱验证属性
set陷阱接收四个参数:
1.trapTarget:用于接收属性(代理的目标)的对象
2.key:要写入的属性键(字符串或者symbol)
3.value:被写入的属性值
4.receiver:操作发生的对象(通常是代理)
let target = { name: target } let proxy = new Proxy(target, { set(trapTarget, key, value, receiver) { if (!trapTarget.hasOwnProperty(key)) { if (isNaN(value)) { throw new TypeError(属性必须时数字) } } return Reflect.set(trapTarget, key, value, receiver) } }) proxy.count = 1 console.log(proxy.count) //1 console.log(target.count) //1 proxy.name = proxy console.log(proxy.name) //proxy console.log(target.name) //proxy proxy.other = other // 这里会报错因为不数字
这个实例每次在外面改变proxy的值时就会出发set函数。
用get陷阱验证对象结构
get接收3个参数
1.trapTarget:用于接收属性(代理的目标)的对象
2.key:要写入的属性键(字符串或者symbol)
3.receiver:操作发生的对象(通常是代理)
let proxy = new Proxy({}, { get(trapTarget, key, receiver) { if (!(key in receiver)) { throw new TypeError(属性 + key + 不存在) } return Reflect.get(trapTarget, key, receiver) } }) proxy.name = proxy console.log(proxy.name) //proxy console.log(proxy.age) // 属性不存在会抛出错误
使用has陷阱因此已有属性
has接收2个参数:
1.trapTarget:用于接收属性(代理的目标)的对象
2.key:要写入的属性键(字符串或者symbol)
let target = { name: target, value: 42 } let proxy = new Proxy(target, { has(trapTarget, key) { if (key === 'value') { return false } else { return Reflect.has(trapTarget, key) } } }) console.log(value in proxy) // false console.log(name in proxy) // true console.log(toString in proxy) // true
用deleteProperty陷阱防止删除属性
deleteProperty接收2个参数:
1.trapTarget:用于接收属性(代理的目标)的对象
2.key:要写入的属性键(字符串或者symbol)
let target = { name: target, value: 42 } let proxy = new Proxy(traget, { deleteProperty(trapTarget, key) { if (key === value) { return false } else { return Reflect.deleteProperty(trapTarget, key) } } }) console.log(value in proxy) // true let result1 = delete proxy.value console.log(result1) // false console.log(value in proxy) // true console.log(name in proxy) // true let result2 = delete proxy.name console.log(result2) // true console.log(name in proxy) // false
当外部要删除proxy的属性就会触发deleteProperty函数
原型代理陷阱(setProptotypeOf,getPrototypeOf)
setProptotypeOf接收2个参数
1.trapTarget:用于接收属性(代理的目标)的对象
2.proto:作为原型使用的对象
let target = {} let proxy = new Proxy(target, { // 访问时调用 getPrototypeOf(trapTarget) { return null }, // 改变时调用 setPrototypeOf(trapTarget, proto) { return false } }) let targetProto = Object.getPrototypeOf(target) let proxyProto = Object.getPrototypeOf(proxy) console.log(targetProto === Object.prototype) //true console.log(proxyProto === Object.prototype) // false console.log(proxyProto) // null Object.setPrototypeOf(target, {}) // 成功 Object.setPrototypeOf(proxy, {}) // 抛出错误
如果正常实现
let target = {} let proxy = new Proxy(target, { // 访问时调用 getPrototypeOf(trapTarget) { return Reflect.getPrototypeOf(trapTarget) }, // 改变时调用 setPrototypeOf(trapTarget, proto) { return Reflect.setPrototypeOf(trapTarget, proto) } }) let targetProto = Object.getPrototypeOf(target) let proxyProto = Object.getPrototypeOf(proxy) console.log(targetProto === Object.prototype) //true console.log(proxyProto === Object.prototype) // true Object.setPrototypeOf(target, {}) // 成功 Object.setPrototypeOf(proxy, {}) // 成功
属性描述符陷阱
defineProperty接收三个参数:
1.trapTarget:用于接收属性(代理的目标)的对象
2.key:要写入的属性键(字符串或者symbol)
3.descriptor:属性的描述对象
let proxy = new Proxy({}, { defineProperty(trapTarget, key, descriptor) { // descriptor 只能接收enumerable, configurable, value, writeable, get, set if (typeof key === symbol) { return false } return Reflect.defineProperty(trapTarget, key, descriptor) }, getownPropertyDescriptor(trapTarget, key) { return Reflect.getownPropertyDescriptor(trapTarget, key) } }) Object.defineProperty(proxy, name, { value: proxy }) console.log(proxy.name) //proxy let nameSymbol = Symbol(name) Object.defineProperty(proxy, nameSymbol, { value: proxy })
在外部调用defineProperty | getownPropertyDescriptor时会触发内部definenProperty | getownPropertyDescriptor方法。
ownKeys陷阱
ownKeys陷阱会拦截外部的Object.keys(),Object.getownPropertyName(),Object.getownPropertySymbols()和object.assign()四个方法
let proxy = new Proxy({}, { ownKeys(trapTarget) { return Reflect.ownKeys(trapTarget).filter(key => { return typeof key !== string || key[0] !== '_' }) } }) let nameSymbol = Symbol(name) proxy.name = proxy proxy._name = private proxy[nameSymbol] = symbol let names = Object.getownPropertyNames(proxy), keys = Object.keys(proxy), symbols = Object.getownPropertySymbols(proxy) console.log(names.length) // 1 console.log(names) // name console.log(keys.length) //1 console.log(keys[0]) // name console.log(symbols.length) //1 console.log(symbols[0]) // symbol(name)
更多编程相关知识,请访问:编程入门!!