Proxy 是 ES6 为了操作对象引入的 API 。Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。
一、概述
Proxy 可以理解为在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截。
使用new Proxy()
生成一个 Proxy 实例:
1
| var proxy = new Proxy(target, handler);
|
target 参数表示所要拦截的目标对象,handler 参数也是一个对象,用来定制拦截行为。看一个最简单的实例:
1 2 3 4
| let obj = {} let p = new Proxy(obj, {}) p.name = 'lily' console.log(obj.name)
|
Vue2 中实现双向数据绑定使用的是 ES5 中的 Object.defineProperty()
,Vue3 实现双向绑定使用的是 Proxy。
二、Proxy 所能代理的范围
实际上 handler
本身就是 ES6 所新设计的一个对象。它的作用就是用来 自定义代理对象的各种可代理操作。它本身一共有13 种方法,每种方法都可以代理一种操作。其 13 种方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| handler.getPrototypeOf()
handler.setPrototypeOf()
handler.isExtensible()
handler.preventExtensions()
handler.getOwnPropertyDescriptor()
andler.defineProperty()
handler.has()
handler.get()
handler.set()
handler.deleteProperty()
handler.ownKeys()
handler.apply()
handler.construct()
|
常见拦截器实例:
get() 实例:
1 2 3 4 5 6 7 8 9 10 11
| let dict = { 'hello': '你好', 'world': '世界' } dict = new Proxy(dict, { get(target, prop) { return prop in target ? target[prop] : `${prop}属性不存在` } }) console.log(dict.hello) console.log(dict.hello1)
|
set() 实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let arr = [] arr = new Proxy(arr, { set(target, prop, val) { if (typeof val === 'number') { target[prop] = val return true } else { return false } } }) arr.push(5) arr.push(6) console.log(arr[0], arr[1], arr.length)
|
用 Proxy 代理时,并不会改变原有的属性和方法,上例中数组的 push() 方法和 length 属性可以正常使用和读取。
has() 实例:
1 2 3 4 5 6 7 8 9 10 11 12
| let range = { start: 1, end: 5 }
range = new Proxy(range, { has(target, prop){ return prop >= target.start && prop <= target.end } }) console.log(2 in range) console.log(9 in range)
|
ownKeys() 实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let userinfo = { username: 'Lily', age: 20, _password: '***' } userinfo = new Proxy(userinfo, { ownKeys(target) { return Object.keys(target).filter(key => !key.startsWith('_')) } })
for (let key in userinfo) { console.log(key) } console.log(Object.keys(userinfo))
|
apply() 实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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)) console.log(sum.call(null, 1, 2, 3)) console.log(sum.apply(null, [1, 2, 3]))
|
construct() 实例:
1 2 3 4 5 6 7 8 9 10 11 12
| let User = class { constructor(name) { this.name = name } } User = new Proxy(User, { construct(target, args, newTarget) { console.log('construct') return new target(...args) } }) console.log(new User('lily'))
|