0
点赞
收藏
分享

微信扫一扫

深入理解 Proxy 和 Reflect-- JavaScript

三次方 2022-03-11 阅读 85

总结:

Proxy 是用来监听js对象的相关操作

  • 如果我们希望监听一个对象的相关操作,那么我们可以先创建一个代理对象(Proxy对象)。
  • 之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作

Reflect 提供操作js对象的方法

它主要提供了很多操作JavaScript对象的方法,有点像Object中操作对象的方法;

  • 比如Reflect.getPrototypeOf(target)类似于 Object.getPrototypeOf()
  • 比如Reflect.defineProperty(target, propertyKey, attributes)类似于Object.defineProperty()

Proxy

相较于 Object.defineProperty 劫持某个属性,Proxy则更彻底,不在局限某个属性,而是直接对整个对象进行代理。

1. Proxy基本使用

语法:

var proxy = new Proxy(target, handler);

Proxy本身是一个构造函数,通过new Proxy生成拦截的实例对象,让外界进行访问;

构造函数中的target就是我们需要代理的目标对象,可以是对象或者数组;
handlerObject.defineProperty中的descriptor描述符有些类似,也是一个对象,用来定制代理规则。

之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作

2. setget 捕获器

如果我们想要侦听某些具体的操作,那么就可以在handler中添加对应的捕捉器(Trap)

set和get分别对应的是函数类型;

  • set函数有四个参数
  • target:目标对象(侦听的对象);
  • property:将被设置的属性key;
  • value:新属性值;
  • receiver:调用的代理对象;
  • get函数有三个参数
  • target:目标对象(侦听的对象);
  • property:被获取的属性key;
  • receiver:调用的代理对象;
const obj = {
  name: "zhLeon521",
  age: 18
}

const objProxy = new Proxy(obj, {
  // 获取值时的捕获器
  get: function (target, key) {
    console.log(`监听到对象的${key}属性被访问了`, target)
    return target[key]
  },

  // 设置值时的捕获器
  set: function (target, key, newValue) {
    console.log(`监听到对象的${key}属性被设置值`, target)
    target[key] = newValue
  }
})

console.log(objProxy.name)
console.log(objProxy.age)

objProxy.name = "blueheart"
objProxy.age = 30

console.log(obj.name)
console.log(obj.age)

在这里插入图片描述

3. Proxy 所有捕获器

所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。

Proxy
在这里插入图片描述

4. Proxy的construct和apply

捕捉器中还有constructapply,它们是应用于函数对象的。

function foo() {

}

const fooProxy = new Proxy(foo, {
  apply: function (target, thisArg, argArray) {
    console.log("对foo函数进行了apply调用")
    return target.apply(thisArg, argArray)
  },
  construct: function (target, argArray, newTarget) {
    console.log("对foo函数进行了new调用")
    return new target(...argArray)
  }
})

fooProxy.apply({}, ["abc", "cba"])
new fooProxy("abc", "cba")

在这里插入图片描述

Reflect

Reflect也是ES6新增的一个API,它是一个对象,字面的意思是反射

Reflect主要提供了很多操作JavaScript对象的方法,有点像Object中操作对象的方法;

  • 比如Reflect.getPrototypeOf(target)类似于 Object.getPrototypeOf()
  • 比如Reflect.defineProperty(target, propertyKey, attributes)类似于Object.defineProperty()

如果我们有Object可以做这些操作,那么为什么还需要有Reflect这样的新增对象呢?

  • 在早期的ECMA规范中没有考虑到这种对 对象本身 的操作如何设计会更加规范,所以将这些API放到了Object上面
  • 但是Object作为一个构造函数,这些操作实际上放到它身上并不合适;
  • 另外还包含一些类似于 indelete操作符,让JS看起来是会有一些奇怪的;
  • 所以在ES6中新增了Reflect,让我们这些操作都集中到了Reflect对象上

Object和Reflect对象之间的API关系

1. Reflect的常见方法

Reflect中有哪些常见的方法呢?它和Proxy是一一对应的,也是13个:
在这里插入图片描述

2. Reflect 的使用

const obj = {
  name: "zhLeon521",
  age: 18
}

const objProxy = new Proxy(obj, {
  get: function (target, key, receiver) {
    console.log("get---------")
    return Reflect.get(target, key)
  },
  set: function (target, key, value) {
    console.log("set---------")
    return Reflect.set(target, key, value)
  }
})

objProxy.name = "blueheart"
console.log(objProxy.name)

在这里插入图片描述

3. Receiver的作用

我们发现在使用gettersetter的时候有一个receiver的参数,它的作用是什么呢?

  • 如果我们的源对象(obj)有settergetter的访问器属性,那么可以通过receiver来改变里面的this
const obj = {
  _name: "zhLeon521",
  get name() {
    return this._name
  },
  set name(newValue) {
    this._name = newValue
  }
}

const objProxy = new Proxy(obj, {
  get: function (target, key, receiver) {
    // receiver是创建出来的代理对象
    console.log("get方法被访问--------", key, receiver)
    console.log(receiver === objProxy)
    return Reflect.get(target, key, receiver)
  },
  set: function (target, key, newValue, receiver) {
    console.log("set方法被访问--------", key, receiver)
    console.log(receiver === objProxy)
    Reflect.set(target, key, newValue, receiver)
  }
})

objProxy.name = "blueheart"
console.log(objProxy.name)

在这里插入图片描述

4. Reflect.construct()

在这里插入图片描述

function Student(name, age) {
  this.name = name
  this.age = age
}

function Teacher() {

}

const stu = new Student("zhLeon521", 18)
console.log(stu)
console.log(stu.__proto__ === Student.prototype)

// 执行Student函数中的内容, 但是创建出来对象是Teacher对象
const teacher = Reflect.construct(Student, ["blueheart", 18], Teacher)
console.log(teacher)
console.log(teacher.__proto__ === Teacher.prototype)

在这里插入图片描述

举报

相关推荐

0 条评论