背景:
Reflect
为了操作对象而提供的新Api
和Proxy
对象一样
特点
- 将
object
对象的一些明显属于语言内部的方法,放到Reflect
上处理; - 修改某些
object
返回的异常结果,让其变得更合理; - 让
object
操作都变成函数行为; reflect
对象上的方法与proxy
对象的方法一一对应,只要是proxy
上的方法,就能在Reflect
对象上找到对应的方法;
console.log('assign' in Object) // object使用命令式行为去操作
console.log(Reflect.has(Object,'assign')) // Object使用函数的行为去操作
下面是我个人关于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官方文档