Proxy
- Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程
- Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
javascript
{
// ES5
let obj = {}
let newVal = ''
Object.defineProperty(obj, 'name', {
get() {
return newVal
},
set(val) {
newVal = val
},
})
obj.name = 'wuchendi'
console.log(obj.name) // wuchendi
}
{
let obj = {
time: '2017-03-11',
name: 'wcd',
_r: 123,
}
let monitor = new Proxy(obj, {
// 拦截对象属性的读取
get(target, key) {
return target[key].replace('2017', '2018')
},
// 拦截对象设置属性
set(target, key, value) {
if (key === 'name') {
return (target[key] = value)
} else {
return target[key]
}
},
// 拦截key in object操作
has(target, key) {
if (key === 'name') {
return target[key]
} else {
return false
}
},
// 拦截delete
deleteProperty(target, key) {
if (key.indexOf('_') > -1) {
delete target[key]
return true
} else {
return target[key]
}
},
// 拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames
ownKeys(target) {
return Object.keys(target).filter((item) => item != 'time')
},
})
console.log('get', monitor.time) // get 2018-03-11
monitor.time = '2018'
monitor.name = 'wuchendi'
console.log('set', monitor.time, monitor) // set 2018-03-11 Proxy {time: "2017-03-11", name: "wuchendi", _r: 123}
console.log('has', 'name' in monitor, 'time' in monitor) // has true false
// delete monitor.time;
// console.log('delete', monitor);
// delete monitor._r;
// console.log('delete', monitor);
console.log('ownKeys', Object.keys(monitor)) // ownKeys ["name", "_r"]
}
{
// apply
let sum = (...args) => {
let num = 0
args.forEach((item) => {
num += item
})
return num
}
sum = new Proxy(sum, {
apply(target, ctx, args) {
return target(...args) * 2
},
})
console.log(sum(1, 2)) // 6
console.log(sum.call(null, 1, 2, 3)) // 12
console.log(sum.apply(null, [1, 2, 3])) // 12
}
{
//constructor new
let User = class {
constructor(name) {
this.name = name
}
}
User = new Proxy(User, {
construct(target, args, newTarget) {
return new target(...args)
},
})
console.log(new User('wuchendi')) // User { name: 'wuchendi' }
}
Reflect
- Reflect 对象与 Proxy 对象一样,也是 ES6 为了操作对象而提供的新 API。 Reflect 对象的设计目的有这样几个。
- 将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty),放到 Reflect 对象上。现阶段,某些方法同时在 Object 和 Reflect 对象上部署,未来的新方法将只部署在 Reflect 对象上
- 修改某些 Object 方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而 Reflect.defineProperty(obj, name, desc)则会返回 false
- 让Object 操作变成函数行为
- Reflect 对象的方法与 Proxy 对象的方法一一对应
javascript
{
let obj = {
time: '2017-03-11',
name: 'wcd',
_r: 123,
}
console.log('Reflect get', Reflect.get(obj, 'time')) // Reflect get 2017-03-11
Reflect.set(obj, 'name', 'wuchendi')
console.log(obj) // { time: '2017-03-11', name: 'wuchendi', _r: 123 }
console.log('has', Reflect.has(obj, 'name')) // has true
}
{
function validator(target, validator) {
return new Proxy(target, {
_validator: validator,
set(target, key, value, proxy) {
if (target.hasOwnProperty(key)) {
let va = this._validator[key]
if (!!va(value)) {
return Reflect.set(target, key, value, proxy)
} else {
throw Error(`不能设置${key}到${value}`)
}
} else {
throw Error(`${key} 不存在`)
}
},
})
}
const personValidators = {
name(val) {
return typeof val === 'string'
},
age(val) {
return typeof val === 'number' && val > 18
},
mobile(val) {},
}
class Person {
constructor(name, age) {
this.name = name
this.age = age
this.mobile = '189****0530'
return validator(this, personValidators)
}
}
const person = new Person('wuchendi', 22)
console.info(person) // Person { name: 'wuchendi', age: 22, mobile: '189****0530' }
person.name = 'dd'
console.info(person) // Person { name: 'dd', age: 22, mobile: '189****0530' }
}