proxy的应用场景

544 阅读2分钟

前日学习了proxy,感觉其很强大,知道了其是用来修改语言的默认行为,属于“元编程”,对编程语言进行编程。但是当时年少无知的我心存疑问:

有什么场景需要我们去修改语言的默认行为呢?

后来查了些资料,这里总结一下,也做抛砖引玉

proxy 用法

let p = new Proxy(target, handler);

target 是用proxy包装的对象,可以是任意类型的对象,比如数组,函数,甚至是另外一个代理。

handler 是一个对象,有13个API,可以劫持默认行为。

proxy 用途

首先我们知道,proxy是做数据劫持用的,具有13个强大API,可以拦截多种操作。

  • 通过拦截set,可以做数据校验
  • 通过拦截apply,可以统计函数调用次数
  • 通过拦截setget,可以实现简单断言
  • 通过拦截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