前日学习了proxy,感觉其很强大,知道了其是用来修改语言的默认行为,属于“元编程”,对编程语言进行编程。但是当时年少无知的我心存疑问:
有什么场景需要我们去修改语言的默认行为呢?
后来查了些资料,这里总结一下,也做抛砖引玉
proxy 用法
let p = new Proxy(target, handler);
target 是用proxy包装的对象,可以是任意类型的对象,比如数组,函数,甚至是另外一个代理。
handler 是一个对象,有13个API,可以劫持默认行为。
proxy 用途
首先我们知道,proxy是做数据劫持用的,具有13个强大API,可以拦截多种操作。
- 通过拦截
set,可以做数据校验 - 通过拦截
apply,可以统计函数调用次数 - 通过拦截
set、get,可以实现简单断言 - 通过拦截
get, 可以实现自定义报错信息 - 通过拦截
apply,可以实现普通函数和构造函数的兼容处理 - 通过拦截
get,实现隐藏属性
代码示例:
// 数据校验
let handler = {
set: function(target, prop, value){
if(prop==='age'){
if(value > 200){
throw new RangeError('超过200岁了!')
}
}
}
}
let person = new Proxy({},handler)
person.age = 300 //超过200岁了!
// 统计函数调用次数
function orginFunction () {}
let handler = {
apply: function(target, thisObj, argumentsList){
console.log('xxx')
return target.apply(thisObj, argumentsList)
}
}
let proxyFunction = new Proxy(orginFunction, handler)
// 实现简单断言, 功能类似console.assert(condition, msg)
let handler = {
set: function(target, prop, value){
if(!value){
console.error(prop)
}
}
}
let assert = new Proxy({}, handler)
assert['Less than 18'] = 18>19 // Error: Less than 18
普通函数和构造函数兼容处理:
class Test {
constructor (a, b) {
console.log('constructor', a, b)
}
}
// Test(1, 2) // throw an error
let proxyClass = new Proxy(Test, {
apply (target, thisArg, argumentsList) {
// 如果想要禁止使用非new的方式来调用函数,直接抛出异常即可
// throw new Error(`Function ${target.name} cannot be invoked without 'new'`)
return new (target.bind(thisArg, ...argumentsList))()
}
})
proxyClass(1, 2) // constructor 1 2