js语法---理解反射Reflect对象和代理Proxy对象

Reflect

基本要点

        反射:reflect是一个内置的全局对象,它的作用就是提供了一些对象实例的拦截方法,它的用法和Math对象相似,都只有静态方法和属性,同时reflect也没有构造器,无法通过new运算符构建实例对象(无实例的全局对象);也就是说reflect相当于一个工具类,只对外提供方法进行使用。

tips 拦截方法:拦截方法是指,通过自身方法去覆盖掉原有的默认方法,这样就只会生效拦截方法的操作,而不执行默认操作(例如,setter的作用,覆盖了原有的赋值操作),

这里使用了reflect的方法就不需要再使用默认的方法了

运用示例

以下使用几个简单的reflect的对比示例

Reflect.ownKeys()

获取对象的所有属性(不限于字符串),返回一个数组 ,作用类似Object.keys

Reflect.ownKeys(target)

target:获取自身属性键的目标对象。
let obj ={
  content: 'hello world',
  length: 11,
  char: 'utf-8'
}

let Keys = Object.keys(obj) // 返回一个由属性名组成的数组
console.log(Keys); // ['content', 'length', 'char']

let keys = Reflect.ownKeys(obj) // 返回一个由属性名组成的数组
console.log(keys); // ['content', 'length', 'char']

         这两个方法的效果一致都能拿到对象所有的属性名,但是Object.keys只能得到对象属性的字符串值,如果一个对象的属性包含symbol类型,就无法将其正确的识别出来,而Reflect.ownKeys就可以做到。

关于symbol类型可以参考:js基本类型---symbol标识符_js symbol属于什么类型-CSDN博客

 

Reflect.has()

判定对象中是否存在某个属性,与 in 操作符 相同,返回Boolean值。

let isChar = Reflect.has(obj, 'char') // 判断属性是否存在
console.log(isChar); // true

 Reflect.get()

返回对象(数组)中指定属性的值

Reflect.get(target, propertyKey[, receiver])

// target 需要取值的目标对象

// propertyKey 需要获取的值的键值

// receiver 如果target对象中指定了getter,receiver则为getter调用时的this值。
let content = Reflect.get(obj, 'content') // 获取属性值
console.log(content); // hello world

 

Reflect.set()

静态方法 Reflect.set() 在一个对象上设置一个属性的值,返回Boolean值

Reflect.set(target, propertyKey, value)
Reflect.set(target, propertyKey, value, receiver)

//target 设置属性的目标对象。

//propertyKey 设置的属性的名称。

//value 设置的值。

// receiver 如果遇到 setter,receiver则为setter调用时的this值。
// obj.content = '你好,世界' // 设置属性值

let setContent = Reflect.set(obj, 'content', '你好,世界') // 设置属性值
console.log(setContent); // true,成功时返回true,否则返回false
console.log(Reflect.get(obj, 'content') ); // 你好,世界
console.log(obj.content); // 你好,世界

 

Reflect.deleteProperty()

静态方法 Reflect.deleteProperty() 允许用于删除属性。它很像delete obj.key,但它是一个函数,成功时返回true,否则返回false,这里的成功是根据结果来看的,如果属性不存在,则返回true,否则返回false

Reflect.deleteProperty(target, propertyKey)

// target 删除属性的目标对象。

// propertyKey 需要删除的属性的名称。

 

delete obj.content // 删除属性
console.log(obj); // {length: 11, char: 'utf-8'}

let deleteContent = Reflect.deleteProperty(obj, 'content') // 删除属性
console.log(deleteContent); // true,成功时返回true,否则返回false,这里的成功是根据结果来看的,如果属性存在,则返回true,否则返回false
console.log(obj); // {length: 11, char: 'utf-8'}
console.log(obj);

为什么使用reflect

Reflect 提供的是一整套反射能力 API,它的调用方式,参数和返回值都是统一风格的,在Reflect 出现之前我们只是利用分散的 API 完成一些动态编程的事情,让动态编程有了一个统一的使用标准

和proxy的关系

proxy是代理对象,它的构造器中就包含了和Reflect相同的方法,当使用proxy代理一个引用类型时,就可以简洁的使用Reflect来实现动态编程的效果,

Reflect和proxy的切合度很高,同时也能够避免使用过多分散API带来的隐性错误(如receiver可以解决this的指向问题)和代码的冗余

总之,reflect整合了一套API用于动态化编程,它可以方便简洁的实现proxy的动态拦截代理

tips 动态编程:响应式数据的原理,当修改页面上的某一个值时,页面效果也随之改变

Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

构造器

const p = new Proxy(target, handler)

// target 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

// handler 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为,比如访问和赋值时的而外操作。

Proxy.revocable()

Proxy.revocable() 方法可以用来创建一个可撤销的代理对象。返回一个包含了代理对象本身和它的撤销方法的可撤销 Proxy 对象。

Proxy.revocable(target, handler);
// target 将用 Proxy 封装的目标对象。可以是任何类型的对象,包括原生数组,函数,甚至可以是另外一个代理对象。

// handler 一个对象,其属性是一批可选的函数,这些函数定义了对应的操作被执行时代理的行为。

代理的意义

        首先代理的对象和原对象的属性和值是绑定一致的,可以理解为指向同一个内存地址,也就是说对代理对象的所有操作结果,最终都会回到原对象中,这个过程就可以实现一些其他操作,例如,改变一个对象的值时,将页面重载一遍,引起页面的变化,这个过程就是响应

一个proxy示例


let obj = {
  name: '张三',
  age: 20,
  sex: '男',
  /**
   * @param {any} val
   */
  set address(val){
    this.address = val;
    return val;
  }
}

const p = new Proxy(obj,{
  get: (obj,key,receiver)=>{
    let res = Reflect.get(obj,key,receiver);
    return res;
  },
  set: (obj,key,val,receiver)=>{
    if(typeof val == 'number'){
      console.log('不能设置数字')
      return;
    }
    let res = Reflect.set(obj,key,val,receiver);
    return res;
  }
})
p.name='李四';
p.age=18;
console.log(obj,p)

可以看到 被代理的对象obj会受到p的影响触发改变,而对代理对象属性赋值时,我们可以在中间穿插其他操作,如这里不允许对属性赋值数字,

完整代码和结果展示

reflect.js

let obj ={
  content: 'hello world',
  length: 11,
  char: 'utf-8'
}

let Keys = Object.keys(obj) // 返回一个由属性名组成的数组
console.log(Keys); // ['content', 'length', 'char']

let keys = Reflect.ownKeys(obj) // 返回一个由属性名组成的数组
console.log(keys); // ['content', 'length', 'char']

let isChar = Reflect.has(obj, 'char') // 判断属性是否存在
console.log(isChar); // true

let content = Reflect.get(obj, 'content') // 获取属性值
console.log(content); // hello world
console.log(obj.content); // hello world

// obj.content = '你好,世界' // 设置属性值

let setContent = Reflect.set(obj, 'content', '你好,世界') // 设置属性值
console.log(setContent); // true,成功时返回true,否则返回false
console.log(Reflect.get(obj, 'content') ); // 你好,世界
console.log(obj.content); // 你好,世界

delete obj.content // 删除属性
console.log(obj); // {length: 11, char: 'utf-8'}

let deleteContent = Reflect.deleteProperty(obj, 'content') // 删除属性
console.log(deleteContent); // true,成功时返回true,否则返回false,这里的成功是根据结果来看的,如果属性存在,则返回true,否则返回false
console.log(obj); // {length: 11, char: 'utf-8'}
console.log(obj);

proxy.js 


let obj = {
  name: '张三',
  age: 20,
  sex: '男',
  /**
   * @param {any} val
   */
  set address(val){
    this.address = val;
    return val;
  }
}

const p = new Proxy(obj,{
  get: (obj,key,receiver)=>{
    let res = Reflect.get(obj,key,receiver);
    return res;
  },
  set: (obj,key,val,receiver)=>{
    if(typeof val == 'number'){
      console.log('不能设置数字')
      return;
    }
    let res = Reflect.set(obj,key,val,receiver);
    return res;
  }
})
p.name='李四';
p.age=18;
console.log(obj,p)

更多内容

更多Reflect和proxy相关的方法和属性可以查看:

Reflect - JavaScript | MDN (mozilla.org)

Proxy() 构造函数 - JavaScript | MDN (mozilla.org)

  • 17
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScriptProxyReflect 是 ECMAScript 6 引入的新特性。它们可以一起使用来创建代理对象,以拦截对对象的访问和操作,从而提供更灵活的控制和定制行为。 Proxy 是一个 JavaScript 内置对象,它允许你拦截并定义基本操作的自定义行为,例如属性访问、函数调用、对象构造等。Reflect 是一个 JavaScript 内置对象,它提供了一组方法,用于在 Proxy 对象上执行默认行为。 使用 ProxyReflect开发人员可以创建具有自定义行为的对象。例如,您可以使用 Proxy 拦截对对象属性的访问,并在 Reflect 上调用默认行为来获取或设置该属性的值。这种灵活性使得开发人员能够更好地控制和自定义应用程序的行为。 下面是一个简单的例子,展示了如何使用 ProxyReflect 创建一个代理对象: ```javascript const obj = { name: 'John', age: 30 }; const handler = { get(target, prop, receiver) { console.log(`Getting ${prop} property`); return Reflect.get(target, prop, receiver); }, set(target, prop, value, receiver) { console.log(`Setting ${prop} property to ${value}`); return Reflect.set(target, prop, value, receiver); } }; const proxyObj = new Proxy(obj, handler); console.log(proxyObj.name); proxyObj.age = 35; ``` 在上面的例子中,我们创建了一个名为 obj 的对象,并将其传递给一个名为 handler 的代理处理程序。处理程序定义了对 get 和 set 操作的拦截,其中在每个操作中都使用 Reflect 调用默认行为。然后,我们创建了一个名为 proxyObj 的代理对象,并将其设置为 obj 的代理。最后,我们访问了 proxyObj 的属性,并将其设置为一个新值。 当我们运行上面的代码时,我们会看到以下输出: ``` Getting name property John Setting age property to 35 ``` 从输出中可以看出,代理处理程序成功地拦截了对代理对象的访问和操作,并使用 Reflect 调用了默认行为。这样,我们就可以更好地控制和自定义我们的应用程序行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值