初识Proxy

99 阅读3分钟

初识Proxy

认识Proxy是从Vue3.0开始,面试的时候遇到过Vue2和Vue3的区别的问题,主要有实现响应式原理上的区别。加上技术分享的时候组内有小伙伴分享过Vue3,也是有一点点了解的。

最开始听到proxy,首先想到的是webpack中的反向代理,可以解决的跨域的问题。ES6的Proxy可以理解为,在目标对象之前架设一层“拦截”,在访问该对象时,比如console.log(obj),都必须先通过这层拦截。所以就可以对外界的访问进行过滤和改写。

一、基础概念

纸上得来终觉浅,绝知此事要躬行。我们先new一个Proxy。

ES6原生提供Proxy构造函数,用来生成Proxy实例。

let proxy = new Proxy(target, handle);
// target参数表示所要拦截的目标对象
// handle参数也是一个对象,用来定制拦截行为
let obj = {
    name'jessica'
}
let proxy = new Proxy(obj, {
    get: ((target, propKey)=>{
        console.log(target);
        console.log(propKey);
        return 35;
    })
})
proxy.name;
/** 会输出3行,
 第一行:{name: 'jessica'};
 第二行:name
 第三行:35
*/

根据结果,在读取proxy.name时,执行get拦截方法,get有三个参数:target, propKey, receiver;target是目标对象也就是变量obj;propKey是属性名;receiver是Proxy实例本身,是可选参数。

固定return 35意味着,任何对这个对象属性访问操作的返回都是35。

二、实例方法及应用

  • get(target, propKey, receiver):拦截对象属性的读取。

    比如:proxy.name或proxy[1]

    应用:1、负索引数组

function reveserArrayGet (arr) {
    let handle = {
        get(target, propKey, receiver){
            // propKey转换为Number方便判断
            let index = Number(propKey);
            if (index < 0) {
                // 代替arr[arr.length-1]
                propKey = String(target.length+index);
            }
            return Reflect.get(target, propKey, receiver);
        }
    }
    return new Proxy(arr, handle);
}
let arr = reveserArrayGet([1,2,7,8]);
arr[-1]// 8

2、缓存:变量限时有效/限制调用次数有效

// 默认有效时间60
const varLimited = (target, time = 60) =>{
    const created = Date.now();
    // 判断是否超出有效时间
    const isExpired = () => Date.now() - created > time *1000;
    return new Proxy(target, {
        //超出时间返回undefined,否则返回正常值
     get(target, propKey)=> (isExpired()? undefined : Reflect.get(target,propKey))
 })
}
let count = varLimited({
    val'jessica'
}, 10);
count.val// jessica
// 10秒以后再访问count.val
count.val// undefined
  • set(target, propKey, value, receiver): 拦截对象属性的设置。

    value是属性值,其他参数可get方法的参数一样。

    比如:proxy.name = '12'或proxy['name']=12。

  • has(target,propKey): 判断某个目标对象是否有该属性名,target为目标对象,propKey是属性名。返回的是一个布尔值。

  • construct(target, args, newTarget): 拦截Proxy实例作为构造函数调用的操作,换个说法就是拦截new命令。

    target是目标对象,args是构造函数的参数对象,newTarget是创造实例的对象,第三个可选。

  • apply(target, object, args): 拦截函数的调用的。

    target为目标对象,object是目标对象上下文this对象,args是目标对象的数组。

  • deleteProperty(target, propKey): 拦截delete proxy[propKey]的操作

  • ownKeys(target): 拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。

  • getOwnPropertyDescriptor(target, propKey): 拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象

  • defineProperty(target, propKey, propDesc): 拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs)

  • preventExtensions(target): 拦截Object.preventExtensions(proxy)

  • getPrototypeOf(target): 拦截Object.getPrototypeOf(proxy), 返回一个对象。

  • isExtensible(target): 拦截Object.isExtensible(proxy)。

  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto)。

参考:ES6之Proxy的巧用www.jianshu.com/p/a831f76e5…

深入理解Proxy 及 使用Proxy实现vue数据双向绑定www.cnblogs.com/tugenhua070…