第十二章 Proxy

概述

  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)