美文网首页
第十二章 Proxy

第十二章 Proxy

作者: A郑家庆 | 来源:发表于2018-12-17 20:02 被阅读0次

    概述

      Proxy用于修改某些操作的默认行为,等同于在语言层面作出修改,所以属于一种元编程,即对编程语言进行编程。
      Proxy可以理解成在目标对象前架设一个"拦截"层,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写,主要用于数组、对象、方法调用自身方法时改变它们的默认行为,每一种方法都有对应的拦截方法。
      ES6原生提供Proxy构造函数,用于生成Proxy实例。

    let proxy = new Proxy(target, handler)
    

      Proxy对象的所有用法都是上面这种形式,不同的只是handler参数的写法,其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
      handler如果是空对象,表示没有拦截,访问handler就等同于访问target。

    Proxy实例的方法

    get()

    get方法用于拦截某个属性的读取操作。

    let person = {
        name: '张三'
    }
    let proxy = new Proxy(person, {
        get (target, property) {
             if (property in target) {
                 return target[property]
             } else {
                  throw new Error('属性不存在')
             }
         }
    })
    proxy.name      // '张三'
    proxy.age       // '属性不存在'
    
    set()

    set方法用于拦截某个属性的赋值操作。

    let validator = {
        set (obj, prop, value) {
            if (prop === 'age') {
                if (!Number.isInteger(value)) {
                    throw new Error('不是整数')
                }
                if (value > 200) {
                    throw new Error('值不能大于200')
                }
            }
            obj[prop] = value
        }
    }
    let person = new Proxy({}, validator)
    person.age = 100
    person.age  // 100
    person.age = 'young'    // 不是整数
    person.age = 300   // 值不能大于200
    
    apply()

    apply方法拦截函数的调用、call和apply操作
    apply方法可以接受3个参数,分别是目标对象、目标对象的上下文和目标对象的参数数组。

    let twice = {
        apply (target, ctx, args) {
           return Reflict.apply(...arguments) * 2
       }
    }
    function sum (left, right) {
        return left + right
    }
    let proxy = new Proxy(sum, twice)
    proxy(1, 2)    // 6
    proxy.call(null, 5, 6)   // 22
    proxy.apply(null, [7, 8])  // 30
    Reflict.apply(proxy, null, [9, 10])   // 38
    

    上面的代码中,每当执行proxy函数(直接调用或call和apply调用)就会被apply方法拦截,直接调用Reflict.apply方法也会被拦截。

    has()

    has方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。

    let stu1 = {name: '张三', score: 59}
    let stu2 = {name: '李四', score: 99}
    let handler = {
        has (target, prop) {
            if (prop === 'score' && target[prop] < 60) {
                console.log(`${target.name}不及格`)
                return false
            }
            return prop in target
        }
    }
    let oproxy1 = new Proxy(stu1, handler)
    let oproxy2 = new Proxy(stu2, handler)
    'score' in oproxy1
    // 张三不及格
    // false
    
    'score' in oproxy2
    // true
    for (let a in oproxy1) {
        console.log(oproxy1[a])
    }
    // 张三  59
    
    for (let b in oproxy2) {
        console.log(oproxy2[b])
    }
    // 李四   99
    

    上面代码中,has拦截只对in循环有效,对for...in循环不生效。

    construct()

    construct方法用于拦截new命令,下面是拦截对象的写法。这个方法接收两个参数:

    • target:目标对象
    • args:构建函数的参数对象
    let P = new Proxy(function () {}, {
        construct: function (target, args) {
            console.log('called:+args.join(',')')
             return {value: args[0] * 10}
          }
       }
    )
    (new p(1)).value
    // 'called: 1'
    // 10
    

    相关文章

      网友评论

          本文标题:第十二章 Proxy

          本文链接:https://www.haomeiwen.com/subject/bpqqkqtx.html