前端知识学习之proxy代理对象

前端proxy代理对象

1.学习背景

学习vue3过程中,发现vue3相比于vue2的最大优势在于,尤雨溪大佬在vue3中使用proxy 代理对象,vue2中使用的双向绑定Object.defineProperty,这两者有什么区别

2.Object.defineProperty

使用方法:

// obj:绑定属性的目标对象
// property: 绑定的属性名
// descriptor: 属性描述(配置),且此参数本身为一个对象
Object.defineProperty(obj, property, descriptor)
  • obj:绑定属性的目标对象
  • property: 绑定的属性名
  • descriptor: 属性描述(配置),且此参数本身为一个对象
    • value: 设置属性默认值
    • writable:设置属性是否能够修改
    • enumerable: 设置属性是否可以枚举,即是否允许遍历
    • configurable: 设置属性是否可以删除或编辑
    • get: 获取属性的值
    • set: 设置属性的值

示例:

//将对象obj 中的值传给target
let obj = {
  age: 18,
  arr: [1, 2, 3]
}
let target = {}

for (let key in obj) {
  Object.defineProperty(target, key, {
    value: obj[key]
  })
}
console.log(target) // 这样我们就获得了obj中的值

》》》》》》》》》》》》》》》》》》》》》》》》
{age: 18, arr: [1, 2, 3]}
2.1 通过writable设置是否可写/修改

使用writable参数判断对象的值是否能修改

let param = {};
Object.defineProperty(param,'nums',{value:18,writable:false});
console.log(param);
param.nums=20;
console.log(param);
》》》》》》》》》》》》》》》》》》》》》》》》
{nums: 18}
{nums: 18}
2.2 通过enumerable设置是否允许遍历
let param = {};
Object.defineProperty(param,'nums',{value:18,enumerable:false});
Object.defineProperty(param,'name',{value:999,enumerable:true});
for(let key in param){
    console.log(key)
}
》》》》》》》》》》》》》》》》》》》》》》》》
name //只打印name
2.3 通过configurable设置属性是否可删
let param = {};
Object.defineProperty(param,'nums',{value:18,configurable:false});
Object.defineProperty(param,'name',{value:999,configurable:true});
delete param.nums
delete param.name
console.log(param)
》》》》》》》》》》》》》》》》》》》》》》》》
{nums: 18} //name 被删掉了
2.4 通过get、set设置值

注意:在使用get和set方法时不能使用value和writable属性

getlet param = {};
Object.defineProperty(param,'nums',{
    get(){
		return 20
	}});
console.log(param.nums)
》》》》》》》》》》》》》》》》》》》》》》》》
20 //输出

setlet param = {};
Object.defineProperty(param,'nums',{
    set(val){
    	console.log(val)
	}});
param.nums=10
》》》》》》》》》》》》》》》》》》》》》》》
10 //输出

3.Proxy代理对象

// Proxy的基础用法如下,它需要传入两个参数
const p = new Proxy(target, handler)

target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
3.1定义一个代理对象
const obj = {
  age: 18
}
const objProxy = new Proxy(obj, {})
console.log(objProxy) // 我们这里打印代理对象
3.2 Proxy捕获器

在定义代理的过程中,handler 被称之为捕获器

下面为三个捕获器:

  • get捕获器
  • set捕获器
  • defineProperty捕获器
get捕获器:
const obj = {
  age: 18
}
const objProxy = new Proxy(obj, {
  get(target, key) {
    console.log('获取对象' + key + '属性的值') // 这里我们可以捕捉到获取对象key的值到操作
    return target[key]
  }
})
console.log(obj.age) // 这里先输出 获取对象age属性的值,   再输出 18

get方法用于拦截对象的读取属性操作,它有三个参数,并且可以返回任何值

  • target:目标对象
  • property: 被读取的属性名
  • receiver: Proxy 或者继承 Proxy 的对象

get方法可以拦截目标对象的以下操作

  • 访问属性:如obj.age
  • 访问原型链上的属性:Object.create(obj)[age]
  • 访问一个内置对象的属性:Reflect.get(arget, propertyKey[, receiver])
set捕获器:
const obj = {
  age: 18
}
const objProxy = new Proxy(obj, {
  set(target, key, val) {
    if(key === 'name' && typeof val === 'string') { // 可以做属性类型检查拦截等操作
      target[key] = val
    } else {
      throw new TypeError("该属性的值必须是String类型");
    }
  }
})
console.log(obj.age)
set方法是设置属性值操作的捕获器。它有四个参数,this会绑定到handler对象上,并且返回一个布尔值
  • target: 目标对象
  • property:将被设置的属性名或一个Symbol
  • value:新属性值
  • receiver: 最初被调用的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是 proxy 本身)。

注意:假设有一段代码执行 obj.name = "mr.z"obj 不是一个 proxy,且自身不含 name 属性,但是它的原型链上有一个 proxy,那么,那个 proxy 的 set() 处理器会被调用,而此时,obj 会作为 receiver 参数传进来。

set方法会拦截目标对象的以下操作:

  • 给属性赋值:objProxy.name = ‘mr.z’
  • 给继承到属性赋值:Object.create(objProxy)[name] = ‘mr.z’
  • Reflect.set() // 这个不做过多讲解

对于以下情况,Proxy会抛出错误

  • 若目标属性是一个不可写及不可配置的数据属性,则不能改变它的值。
  • 如果目标属性没有配置存储方法,即 [[Set]] 属性的是 undefined,则不能设置它的值。
  • 在严格模式下,如果 set() 方法返回 false,那么也会抛出一个 TypeError异常。
defineProperty 捕获器
let obj = new Proxy({}, {
  defineProperty(target, property, descriptor) {
    console.log('设置的属性: ' + prop);
    return true;
  }
});

var desc = { configurable: true, enumerable: true, value: 'mr.z' };
Object.defineProperty(obj, 'name', desc); // "设置的属性: name"

defineProperty方法有三个参数,并且它的返回值必须是一个布尔值

  • target:目标对象
  • property:待检索其描述的属性名
  • descriptor:待定义或修改的属性的描述符

Proxy中共有13个捕获器,它们用于我们对对象、函数的方法调用监听。下面是Proxy捕获器以及它们的触发条件。

对象中的方法对应触发条件
handler.getPrototypeOf()Object.getPrototypeOf 方法的捕捉器
handler.setPrototypeOf()Object.setPrototypeOf 方法的捕捉器
handler.isExtensible()Object.isExtensible 方法的捕捉器
handler.preventExtensions()Object.preventExtensions 方法的捕捉器
handler.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor 方法的捕捉器。
handler.defineProperty()Object.defineProperty 方法的捕捉器
handler.has()in 操作符的捕捉器
handler.get()属性读取操作的捕捉器
handler.set()属性设置操作的捕捉器
handler.deleteProperty()delete 操作符的捕捉器
handler.ownKeys()Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器
handler.apply()函数被apply调用操作的捕捉器
handler.construct()new 操作符的捕捉器
  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值