关于 Reflect 的笔记

背景:Reflect 为了操作对象而提供的新ApiProxy对象一样

特点

  1. object 对象的一些明显属于语言内部的方法,放到Reflect 上处理;
  2. 修改某些object返回的异常结果,让其变得更合理;
  3. object操作都变成函数行为;
  4. reflect对象上的方法与proxy对象的方法一一对应,只要是proxy上的方法,就能在Reflect对象上找到对应的方法;
 console.log('assign' in Object) // object使用命令式行为去操作
​
 console.log(Reflect.has(Object,'assign'))  // Object使用函数的行为去操作

下面是我个人关于Reflect的思维导图

Reflect的简介思维导图

Reflect方法中第一个参数不是对象的话,会报错

1:使用Reflect.get()方法

语法:Reflect.get(target,name,receiver)

接收三个字段

  • target:目标对象

  • name:属性名

  • receiver: this绑定的对象 接收对象

 let myObject = {
​
   foo: 1,
​
   bar: 2,
​
   get baz () {
​
•    return this.foo + this.bar
​
   }
​
  }
​
  console.log(Reflect.get(myObject,'foo')) // 1
​
  console.log(Reflect.get(myObject,'bar')) // 2
​
  console.log(Reflect.get(myObject,'baz')) // 3

1.1 使用receiver来指定数据

 let myObject1 = {
​
   foot: 1,
​
   bar: 2,
​
   get boo () {
​
•    return this.foot + this.bar
​
   }
​
  }
​
​
​
  let myReceiver = {
​
   foot: 2,
​
   bar: 4,
​
  }

name 在有get的情况下,则读取函数的this绑定receiver (this指向发生了改变)

 console.log('访问',myObject1.boo) // 3
​
 console.log('访问2',Reflect.get(myObject1,'boo',myReceiver)) // 6

tips: Reflect.get()的第一个参数必须是一个对象,否则会报错

2:使用Reflect.set()方法

通过Reflect.set方法设置target的name属性等于value

语法:Reflect.set(target,name,value,receiver)

接收四个字段

  • target:目标对象

  • name:属性名

  • value:

  • receiver: this绑定的对象 接收对象
  let myObject2 = {
​
   foot: 1,
​
   set bar (value) {
​
•    return this.foot = value
​
   }
​
  }
  console.log('读取原有属性的值:',myObject2.foot) // 1
​
  Reflect.set(myObject2,'foot', 2)
​
  console.log('Reflect.set修改原有属性的值:',myObject2.foot)// 2
​
  Reflect.set(myObject2,'bar', 6)
​
  console.log('通过Reflect.set修改原有属性的值:',myObject2.foot) // 6

如果name属性设置了赋值函数,则赋值函数的this绑定receiver

  let myObject3 = {
​
   foo: 3,
​
   set bar (value) {
​
•    return this.foo = value
​
   }
​
  }
​
​
​
  let receiverMyObject = {
​
   foo: 0,
​
  }

通过Reflect.set()修改foo的值

Reflect.set(myObject3,'bar',2,receiverMyObject)
​
console.log('target原有的值',myObject3.foo)  // 3
​
console.log('this指向的receiver发生了变化:',receiverMyObject.foo) // 2

3:使用Reflect.has()方法

通过 Reflect.has()方法查看属性是否存在,返回boolean值

let obj1 = { a: 1 }

旧方法

console.log('a' in obj1) // true 

使用 Reflect.has()方法

语法:Reflect.has(obj,name)

console.log(Reflect.has(obj1,'a')) // true

4:删除属性操作

语法:Reflect.deleteProperty(obj,name)

 let obj2 = { title: '标题信息', name: '名称信息' }
 console.log('对象原有内容:', obj2) // {title: '标题信息', name: '名称信息'}

旧方法

delete obj2.title
console.log('使用旧方法删除的值:', obj2) // {name: '名称信息'}

使用Reflect.deleteProperty()进行删除

Reflect.deleteProperty(obj2,'name')
console.log('使用Reflect.deleteProperty()方法删除后的:', obj2) // { }

5:constructor的使用

  function Test (value) {
​
   this.value1 = value
​
  }

通过new实例化对象

let objFun = new Test('测试')
console.log('objFun:',objFun) // Test {value1: '测试'}

通过Reflect.construct()调用构造函数

let objFun2 = Reflect.construct(Test,['初始化声明'])
console.log('objFun2:',objFun2) // Test {value1: '初始化声明'}

6: Reflect.getPrototypeOf()获取对象的__proto__属性

tips: 下面几个方法是读取函数的__proto__属性

之前的写法:通过Object.getPrototypeOf() 获取指定对象的原型对象

console.log(Object.getPrototypeOf(objFun))

如果Object.getPrototypeOf()传入的不是对象,会先转换成对象,再运行

console.log(Object.getPrototypeOf(2)) // Number {0, constructor: ƒ, toExponential: ƒ, toFixed: ƒ, toPrecision: ƒ, …}
​
console.log('旧写法:',Object.getPrototypeOf(objFun) === Test.prototype) //  旧写法: true

Reflect只接收对象,不是对象的话会报错

console.log(Reflect.getPrototypeOf(2)) // 报错,提示Reflect.getPrototypeOf()第一个参数必须是对象
console.log('Reflect写法:',Reflect.getPrototypeOf(objFun) === Test.prototype) // Reflect写法: true

7:Reflect.apply(fung,thisArg,args)

一般来说,如果要绑定一个函数的this对象,可以这样写fn.apply(obj, args),但是如果函数定义了自己的apply方法,就只能写成Function.prototype.apply.call(fn, obj, args),采用Reflect对象可以简化这种操作

 let arr1 = [12,14,16,18,20,22,24,26]
​
  let youngest1 = Math.min.apply(Math,arr1)  // 12 通过this指向到Math,并传进去一个新的数组,获取最小值
​
  console.log('youngest1:',youngest1) // youngest1: 12
​
  let newMax1 = Math.max.apply(Math,arr1)  // 26  获取最大值
​
  console.log('newMax1:',newMax1) // newMax1: 26
​
  let type = Object.prototype.toString.call(youngest1)
​
  console.log('type:',type) // type: [object Number]

使用Reflect重写上面的代码

let arr2 = ['12','14','16','18','20','22','24','26']
​
let youngest2 = Reflect.apply(Math.min,Math,arr2)
​
console.log('使用Reflect取最小值:',youngest2)  // 使用Reflect取最小值: 12
​
let newMax2 = Reflect.apply(Math.max,Math,arr2)
​
console.log('使用Reflect取最大值:',newMax2)  // 使用Reflect取最大值: 26
​
let type1 = Reflect.apply(Object.prototype.toString,youngest2,[])
​
console.log('使用Reflect取值:',type1) // 使用Reflect取值: [object Number]

8:通过Reflect.defineProperty定义对象属性

和Object.defineProperty()方法相同,后期,Object.defineProperty()方法会被废除

    function MyData () {}

通过Object旧方法创建默认属性 

  Object.defineProperty(MyData,'now',{

      value: '11'

    })

声明实例   

let date1 = new MyData()

console.log('date1:',date1)

通过Reflect新方法创建属性

Reflect.defineProperty(MyData,'hh',{

  value: '12'

})

声明实例 

let date2 = new MyData()

console.log('date2:',date2)

通过proxy声明一个实例 

  let p = new Proxy({},{

      defineProperty(target,prop,descriptor) {

        console.log(descriptor)

        return Reflect.defineProperty(target,prop,descriptor)

      }

    })

在实例上创建属性 foor并赋值

p.foor = 'bar'

console.log('打印:',p) // Proxy(Object) {foor: 'bar'}

9:Reflect.getOwnPropertyDescription() 获取指定属性的描述对象

let object = {};

    Object.defineProperty(object, 'hidden', {

      value: '1',

      enumerable: false,

    });

语法:Reflect.getOwnPropertyDescription(target,name)

  • target: 目标对象
  • name: 指定属性名称
// 旧写法
var theDescriptor = Object.getOwnPropertyDescriptor(object, 'hidden');

console.log('theDescriptor:',theDescriptor)
// 新写法

var newtheDescriptor = Reflect.getOwnPropertyDescriptor(object, 'hidden');

console.log('newtheDescriptor:',newtheDescriptor)

区别:

  • Object.getOwnPropertyDescription()第一个参数如果不是对象,会返回undefined,后期会废弃该方法
  • Reflect.getOwnPropertyDescription()第一个参数如果不是对象,会报错,提示参数非法

10:Reflect.isExtensible() 是否可扩展

    let myEbject3 = {

      a: 1,

      b: 2,

    }

   表示当前对象是否可扩展 true为可扩展,false为不可扩展

console.log(Object.isExtensible(myEbject3))  // true

console.log(Reflect.isExtensible(myObject3)) // true

preventExtensions()调用之后,严格模式下会报错,非格严模式下静默失败

Reflect.preventExtensions(myEbject3)   // 禁止扩展

console.log(Reflect.isExtensible(myEbject3)) // false

seal 密封属性,不可扩展,已有成员configurable会被设置为false

Object.seal(myEbject3) // 密封对象操作

console.log(Reflect.isExtensible(myEbject3)) // false

freeze 冻结对象 不可扩展且密封,已有成员的configurable及writable都被设置为false

Object.freeze(myEbject3)  // 冻结对象操作

console.log(Reflect.isExtensible(myEbject3)) // false

11:Reflect.ownKeys(target)

用于返回对象的所有属性

  • 旧方法:Object.getOwnPropertyNames()
  • 旧方法:Object.getOwnPropertySymbols()
   let myObject45 = {

      foo: 1,

      boor: 2,

      [Symbol.for('bridge')]: 3,

      [Symbol.for('hear')]: 6

    }

    console.log('普通属性:',Object.getOwnPropertyNames(myObject45))  // 普通属性: (2) ['foo', 'boor']

    console.log('symbol定义的属性:',Object.getOwnPropertySymbols(myObject45)) // symbol定义的属性: (2) [Symbol(bridge), Symbol(hear)]



    console.log('查到所有的属性:', Reflect.ownKeys(myObject45))  // 查到所有的属性:(4) ['foo', 'boor', Symbol(bridge), Symbol(hear)]

12:小结案例

   

const queryObserve = new Set()



    // 添加监听,fn监听的内容

    let observe = (fn) => queryObserve.add(fn)



    // 声明实例,传入handler处理

    let observable = obj => new Proxy(obj,{set})



    function set(target,key,value,receiver) {

      const result = Reflect.set(target,key,value,receiver)

      queryObserve.forEach(observe => observe())

      return result

    }



    // 实例创建之后,传入数据

    const person = observable({

      name: '张三丰',

      age: 20

    });



    function print() {

      // 这里打印数据

      console.log(`${person.name}, ${person.age}`)

    }



    // 传入打印的函数

    observe(print);

    // 当修改数据时,触发上面的监听,就会打印数据

    person.name = '李鸿章';

    // 输出

    // 李鸿章, 20

关于Reflect部分的笔记,基本就到这了,更多详情请查阅阮一峰老师ES6官方文档

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值