当前位置:   article > 正文

JavaScript 中Proxy(代理)和Reflect(反射)基础知识_js 使用reflect

js 使用reflect

JavaScript 中Proxy(代理)和Reflect(反射)基础知识

  最近在Vue3项目开发中,我们经常使用与Proxy和Reflect相关的函数。这些函数以各种形式出现在Vue3 Reactivity函数、各种库和框架中。然而,对于JavaScript Proxy的概念和使用方法,许多人可能不太熟悉。因此,下面我将通过一个例子来更好地解释Proxy和Reflect的使用方法。

  Reflect和Proxy是EC6引入的两个新功能,可以帮助开发人员更轻松地操作和控制对象。但是,我发现许多同事的JavaScript知识体系还停留在ES5时代,对Proxy和Reflect的使用并不是很理解。在Vue3项目中反应出来的现象是使用反射函数的时候并不是很理解它们的底层原理。因此,我希望这篇文章能帮助他们更好地理解和学习Proxy和Reflect。

JavaScript 特性 this与“bind“和“call“,“apply“的理解
JavaScript 特性 Promise 函数
JavaScript 特性 map、forEach、filter 和 find 与箭头函数的使用
JavaScript 特性 Destructuring 语法
JavaScript 特性 Proxy(代理)和Reflect(反射)
JavaScript 特性 Object.assign与Getter,Setters 和 definePropert
JavaScript 中使用 XMLHttpRequest

JavaScript 中Proxy使用

  Proxy是一种可以代替直接访问对象的方式,在处理对象时可以改变原有的处理方式或者增加额外的处理。

举个例子,在情人节我们想给女朋友送花,可以选择在当地花店购买并选择送货上门服务,或者在美团中购买鲜花。在这两种情况下,花店员工会直接将鲜花送到女朋友手中。但是通过美团购买鲜花,我们还可以获得一些额外的服务,例如检查订单状态、到达地点、为女朋友留言和对商店进行评分等等。这些额外的服务可以被看作是代理服务,因为它们并不是原始交付。

  虽然Proxy的概念很多人都已经看过网上的大量文档,但是实际上使用代码来演示Proxy的用法可能更容易理解。例如,如果你创建了一个用户对象,想要获取其中的name属性值,通常可以通过以下代码实现:

const user = {
  name: 'zht',
};
console.log(user.name)
  • 1
  • 2
  • 3
  • 4

  使用Proxy时,我们可以通过创建一个新的Proxy对象proxy_user,然后通过这个代理对象来访问我们所需要的属性和方法。为了创建这个代理对象,我们使用了JavaScript中的new Proxy()语法,这个语法会返回一个新的代理对象。

  代理对象proxy_user的使用方式与普通对象类似,但是在获取和设置属性时会有所不同。在访问属性时,代理对象会拦截这个操作,从而允许我们修改属性的值或者执行一些额外的操作。同时,我们可以在代理对象中设置一些附加的逻辑和操作,从而为我们的应用程序增加更多的功能和灵活性。

下面是一个简单的示例代码,演示了如何创建一个代理对象并使用它来访问属性:

let user = {
  name: "zht"
}
let proxy_user = new Proxy(user,{})
alert(proxy_user.name)
  • 1
  • 2
  • 3
  • 4
  • 5

  在上面的例子中,我们使用了Proxy函数并让其代理user对象。Proxy语法接受两个参数,第一个参数是目标对象,即我们要对其进行代理的对象。在这里,我们的目标对象是user对象。第二个参数是一个空对象,它包含代理逻辑部分的处理程序。我们可以通过添加处理程序来修改代理对象的行为,例如在访问属性时添加一些额外的逻辑。

代理对象 = Proxy(目标,处理程序)

let proxy = new Proxy(target, handler)

  在 handler 中,可以通过编写预先定义的方法称为 traps 来添加额外的处理。traps 包括一个 get 方法用于获取值和一个 set 方法用于设置值。通过 handler 向对象的操作添加额外的处理。如果 handler 为空,则可以执行与原始对象相同的操作。

我们将演示Proxy中的 get 和 set 方法,deleteProperty 方法的使用。

1 Proxy中get方法

  可以使用 handler 中的 get 方法来获取对象的值,并添加新的处理逻辑。

var user = {
  name: "zht",
  dept: "部门一"
}
var proxy_user = new Proxy(user,{  
	  get(target,prop){
		console.log(target +'和' + prop +'处理业务')
		return target[prop]
	  }
  })
alert(proxy_user.name)
========= 结果打印 ========
[object Object]和name处理业务
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

  在 handler {} 中加入了 get 方法,该方法的参数包括 target 和 prop。其中,target 对应 user,而 prop 对应于指定的 firstName,即 proxy_user.name。当使用代理访问时,与之前相同,可以使用 proxy_user.name进行访问。在 handler 中添加了 get 方法后,访问 firstName 属性时,get 方法会自动执行,并显示以下消息。

  • target对应user
  • prop对应name

2 Proxy中set方法处理

  确认一下常规对象的值设置方法。我们向 user 对象添加了 name属性,并将其值设置为 kaimi。

var user = {
  name: "zht",
  dept: "部门一"
}
let proxy_user = new Proxy(user, {});
proxy_user.name = "kaimi";
console.log(proxy_user.name);
console.log(user.name);
========= 结果打印 ========
kaimi // proxy_user.name
kaimi // user.name
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

  用 set 方法设置它。可以看到通过 proxy_user 设置的 name也反映在了原来的用户对象中。然后向处理程序添加一个设置方法。

var user = {
  name: "zht",
  dept: "部门一"
}

let proxy_user = new Proxy(user,{
  get(target,prop){
    console.log(target +'和' + prop +'处理业务')
    return target[prop]
  },
  set(target,prop,value){
    console.log(target )
    console.log('变化' + prop + '属性值变化值' + value )
    target[prop] = value
  }
})
proxy_user.name = "kaimi";
console.log(proxy_user.name);
console.log(user.name);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

set方法参数中。

  • target对应user
  • prop对应name
  • value对应zht。

您还可以为 proxy_user 设置一个 for 循环,以遍历其中的值。

var user = {
  name: "zht",
  dept: "部门一"
}

let proxy_user = new Proxy(user,{
  get(target,prop){
    console.log(target +'和' + prop +'处理业务')
    return target[prop]
  },
  set(target,prop,value){
    console.log(target )
    console.log('变化' + prop + '属性值变化值' + value )
    target[prop] = value
  }
})

proxy_user.name = "kaimi";
for (key in proxy_user) {
  console.log(proxy_user[key]);
}
========= 结果打印 ========
{name: 'zht', dept: '部门一'}
zhtbs.html:25 变化name属性值变化值kaimi
zhtbs.html:20 [object Object]和name处理业务
zhtbs.html:33 kaimi
zhtbs.html:20 [object Object]和dept处理业务
zhtbs.html:33 部门一
  • 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

通过前面的讲解,我们已经了解到了通过代理(proxy)对象可以添加新的处理逻辑和新的属性。

3 deleteProperty 方法

deleteProperty 方法用于删除对象属性。

var user = {
  name: "zht",
  dept: "部门一"
}

let proxy_user = new Proxy(user,{
  get(target,prop){
    console.log(target +'和' + prop +'处理业务')
    return target[prop]
  },
  set(target,prop,value){
    console.log(target )
    console.log('变化' + prop + '属性值变化值' + value )
    target[prop] = value
  },
   deleteProperty(target, prop) {
    console.log(target + "开始" + prop + "删除");
    delete target[prop];
  },
})

console.log(proxy_user.dept);
delete proxy_user.dept;
console.log(proxy_user.dept);
========= 结果打印 ========
[object Object]和dept处理业务
部门一
[object Object]开始dept删除
[object Object]和dept处理业务
undefined
  • 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

执行时,将显示消息“[object Object]开始dept删除”。它说未定义,因为删除后正在访问该属性。

  • target对应user
  • prop对应name

JavaScript 中Reflect使用

  Reflect 是一个内置的对象,提供了一组有用的方法,用于操作对象和函数。它提供了一种与 Proxy 对象交互的方法,使开发人员可以使用相同的方法来处理对象和函数,同时提供更多的操作和控制选项。在使用 Reflect时候可以使代码更加简洁和易于理解,同时还提供了更多的操作和控制选项。

使用 Reflect,您可以按以下方式获取对象属性的值。在使用 Reflect 时,无需使用 new 等方式创建实例。

var user = {
  name: "zht",
  dept: "部门一"
}
console.log(Reflect.get(user,'name')) 
  • 1
  • 2
  • 3
  • 4
  • 5

您还可以使用 set 方法添加新属性。

var user = {
  name: "zht",
  dept: "部门一"
}
Reflect.set(user, "post", "管理员");
console.log(Reflect.get(user, "post"));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

1 Reflect 和 Proxy联合使用

通过使用 Reflect函数,可以重写Proxy中的 get 和 set 方法。用 Reflect.get(target,prop.receiver) 替换 target[prop]。

var user = {
  name: "zht",
  dept: "部门一"
}

let proxy_user = new Proxy(user,{
  get(target,prop,receiver){
    console.log(receiver) //添加收器的内容
    return Reflect.get(target,prop,receiver)
  },
})
console.log(proxy_user.name)
========= receiver结果打印 ========
{name: 'zht', dept: '部门一'}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

get 方法中,第三个参数 receiver 被添加了进来。receiver 是指代理本身,您可以使用 console.log(receiver) 来检查其内容。

Reflect.get方法的参数也可以使用arguments对象进行设置,如下所示。arguments对象包含了target、prop和receiver三个参数对象。

var user = {
  name: "zht",
  dept: "部门一"
}
let proxy_user = new Proxy(user,{
  get(target,prop,receiver){
    return Reflect.get(...arguments);
  },
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Reflect.get arguments 也可以使用 arguments 设置如下。

var user = {
  name: "zht",
  dept: "部门一"
}
const handler = {
  get(target,prop,receiver){
    return Reflect.get(...arguments);
  },
  set(target, prop, value, receiver) {
    console.log(`属性名称 ${prop} 它的值 ${value}`);
    const success = Reflect.set(target, prop, value, receiver);
  }
};
let proxy_user = new Proxy(user,handler)
proxy_user.dept= "部门三";
proxy_user.post= "管理员";
console.log(proxy_user);
========= 结果打印 ========
属性名称 dept 它的值 部门三
属性名称 post 它的值 管理员
Proxy {name: 'zht', dept: '部门三', post: '管理员'}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • target对应user
  • prop对应变化属性名称
  • value对应zht。
  • receiver对应代理对象

我们已经了解了如何使用 Reflect 和 Proxy 来创建一个可观察对象,并为其添加一些附加行为。这种方法可以帮助我们更好地控制和操作对象,让我们的代码更加健壮和可靠。

2 Reflect.get方法

Reflect.get 方法不仅可以用于对象,还可以用于数组。

通过传递第二个参数 1,可以获取数组索引为 1 的元素。下面是代码示例:

const users = ['zht', 'kaimi', '张**'];
console.log(Reflect.get(users, 1));//zht
========= 结果打印 ========
zht
  • 1
  • 2
  • 3
  • 4

3 Reflect.set方法

使用 set 来添加对象的属性与值。

const user = {
  name: "zht",
  dept: "部门一"
};
Reflect.set(user, 'name', '张**');
console.log(user);
========= 结果打印 ========
zhtbs.html:19 {name: '张**', dept: '部门一'}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3 Reflect.deleteProperty

可用于从对象中删除属性。

const user = {
  name: "zht",
  dept: "部门一"
};
Reflect.deleteProperty(user, 'name');
console.log(user);
========= 结果打印 ========
{ dept: '部门一'}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Reflect 中的所有对应方法如下:

  • Reflect.apply():调用一个函数。
  • Reflect.construct():创建一个实例对象。
  • Reflect.defineProperty():定义一个对象的属性。
  • Reflect.deleteProperty():删除一个对象的属性。
  • Reflect.get():获取一个对象的属性值。
  • Reflect.getOwnPropertyDescriptor():获取一个对象的属性描述符。
  • Reflect.getPrototypeOf():获取一个对象的原型。
  • Reflect.has():检查一个对象是否有某个属性。
  • Reflect.isExtensible():检查一个对象是否可扩展。
  • Reflect.ownKeys():获取一个对象的所有属性名,包括 Symbol 类型的属性。
  • Reflect.preventExtensions():使一个对象变为不可扩展。
  • Reflect.set():设置一个对象的属性值。
  • Reflect.setPrototypeOf():设置一个对象的原型。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/140287
推荐阅读
相关标签
  

闽ICP备14008679号