一 Proxy是什么
- Proxy 一般是用来架设在目标对象之上的一层拦截,来实现对目标对象访问和修改的控制。Proxy是一个构造函数,使用时必须搭配
new
操作符,直接调用会报错的。 - Proxy 构造函数接受两个参数:
第一个参数: 需要拦截的对象
第二个参数: 对象和数组或者函数 - 返回一个新的对象,不是原来的对象
栗子:
let person = {
name:"fsd",
age:23
}
let person2 = new Proxy(person,{
//target: 目标对象person
//prop: 代理的属性 name
//receiver: 代理后的对象 person2
//value: 设置新的值
get(target,prop,receiver) {
console.log(target,prop,receiver)
//{name: "fsd", age: 23} "name Proxy {name: "fsd", age: 23}
//拦截后可以增强方法
console.log(`增强方法比如: i am ${prop}`)
return target[prop]
},
set(target,prop,value,receiver) {
}
});
console.log(person,person2);
console.log(person == person2)//false
console.log(person2.name)//fsd
- 13种拦截操作 方法
[图片上传失败...(image-d5faa5-1604487244374)] - get(target, prop, receiver):拦截对象属性的访问。
- set(target, prop, value, receiver):拦截对象属性的设置,最后返回一个布尔值。
- apply(target, object, args):用于拦截函数的调用,比如 proxy()。
- construct(target, args):方法用于拦截 new 操作符,比如 new proxy()。为了使 new操作符在生成的Proxy对象上生效,用于初始化代理的目标对象自身必须具有 [[Construct]] 内部方法(即 new target 必须是有效的)。
- has(target, prop):拦截例如 prop in proxy的操作,返回一个布尔值。
- deleteProperty(target, prop):拦截例如 delete proxy[prop] 的操作,返回一个布尔值。
- ownKeys(target):拦截 Object.getOwnPropertyNames(proxy)、Object.keys(proxy)、for in 循环等等操作,最终会返回一个数组。
- getOwnPropertyDescriptor(target, prop):拦截 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),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
二 Proxy和 Object.defineProperty 区别?
在 Proxy对象出现之前,javascript中提供了Object.defineProperty,允许对对象的getter/setter进行拦截,那么两者的区别在哪里?
- Object.defineProperty 无法一次性监听对象所有属性,必须遍历或者递归来实现
- Object.defineProperty 无法监听到新增加的属性,而Proxy可以增加的属性,因此vue2.x版本需要通过 vm.set(obj,prop,value)这种形式添加。
- Object.defineProperty 无法响应式数组操作,可以监听数组的变化(地址),无法监听到对 数组内置的方法(push shift pop unshift) 进行相应。vue2.x通过重写原型方法来实现相应。
- Proxy拦截方式多
- Object.defineProperty 兼容性比较好,Proxy 支持不了IE全系列
三 Proxy拦截方法的用法
-
拦截get用法
get方法接受3个参数
target: 目标对象;prop:目标属性;receiver:proxy实例(代理对象)- 基于 get 方法的特性,可以实现很多实用的功能,比如在对象里面设置私有属性(一般定义属性我们以 _ 开头表明是私有属性) ,实现禁止访问私有属性的功能。
const person = { name:"tom", _sex:"male"//比如私有属性不可访问 } const proxyPerson = new Proxy(person,{ get(target,prop) { if(prop[0] === "_") { throw new Error(`${prop} is private attribute`) } return target[prop]; } }) proxyPerson.name // tom proxyPerson._sex //Uncaught Error: _sex is private attribute
- 我们可以给对象中未定义属性设置默认值
undefined
const defaults = (obj,initValue) => { return new Proxy(obj,{ set(target,prop,receiver) { if(prop in target) { return target[prop] } return initValue } }) } person = defaults(person,undefined); person.name //tom console.log(person.age)//undefined
-
set用法
set方法接受3个参数
target: 目标对象;prop:目标属性;value:属性值; receiver:proxy实例(代理对象)- 表单验证
// 验证规则 -- 类似设计模式策略模式中 策略集合 const validators = { name: { validate(value) { return value.length > 6; }, message: '用户名长度不能小于六' }, password: { validate(value) { return value.length > 10; }, message: '密码长度不能小于十' }, moblie: { validate(value) { return /^1(3|5|7|8|9)[0-9]{9}$/.test(value); }, message: '手机号格式错误' } } // 验证方法 -- 类似设计模式策略模式中 策略使用 function validator(obj, validators) { return new Proxy(obj, { set(target, key, value) { const validator = validators[key] if (!validator) { target[key] = value; } else if (validator.validate(value)) { target[key] = value; } else { alert(validator.message || ""); } } }) } let form = {}; form = validator(form, validators); form.name = '666'; // 用户名长度不能小于六 form.password = '113123123123123';
网友评论