初识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…