1.Reflect被设计的目的
(1)原先Object对象上一些属于语言内部的方法,在未来都会被部署到Reflect上去。而现阶段这些方法是在Object和Reflect上并存的。例如Object.defineProperty等方法。
(2)目前Object上某些方法的返回结果,部署到Reflect上之后会变得越来越合理。比如Object.defineProperty在定义属性失败时会抛出错误,而Reflect.defineProperty则直接返回false。
(3)将delete obj[name]这种命令式操作改成函数式操作
(4)Reflect对象的方法与Proxy对象上的方法一一对应,这样在使用Proxy代理方法的时候,如果只是想要在方法原有功能上添加一些功能,则可以调用Reflect上的方法来完成默认行为,然后再添加自己想要的逻辑功能来增强方法。
2.Reflect的静态方法
(1)Reflect.get(target, name, receiver)
1.target表示目标对象,传入的必须是对象,不是对象会报错。
2.name 要获取的属性名
3.receiver 与target对象中设置了get函数的属性里的this绑定。
let target = {
a: 1,
b: 2,
get c() {
return this.d + this.e
}
}
let receiver = {
d: 3,
e: 4
}
Reflect.get(target, 'c', receiver) // 返回7
(2)Reflect.set(target, name, value, receiver)
1.target表示目标对象,不是目标对象则会报错
2.name表示要设置的属性
3.value表示要设置的属性值
4.receiver 表示要操作的对象优先级高于第一个参数,并与设置了set函数中的this绑定
let obj = {
foo: 1,
boo: 2,
set b(val) {
return this.foo = val
}
}
let myObj ={
foo: 2,
boo: 3
}
Reflect.set(obj, 'b', 3, myObj)
Reflect.set(obj, 'boo', 4, myObj)
console.log(myObj.foo, obj.foo) // 3, 1
console.log(myObj.boo, obj.boo) // 4, 2
Reflect 和 Proxy联合使用的例子
let obj = {
a: 1
}
let handler = {
set(target, key, name, receiver) {
console.log('set')
Reflect.set(target, key, name, receiver)
},
defineProperty(target, key, attr) {
console.log('defineProperty')
Reflect.defineProperty(target, key, attr)
}
}
let myObj = new Proxy(obj, handler)
myObj.a = 2
上述代码Proxy对赋值行为进行了拦截,调用了handler对象中的set方法,set方法中又调用了Reflect.set方法,同时传入了receiver对象, 因为receiver对象总是指向proxy实例,所以又被defineProperty拦截
(3)Reflect.has(obj, name)
1.es6中使用Reflect.has()方法来取代ES5 Object中in运算符
2.obj参数必须是对象否则会报错
let obj = {
a: 1
}
// es5
a in obj // true
// es6
Reflect.has(obj, 'a') // true
(4)Reflect.deleteProperty(obj, name)
1.es6中使用Reflect.deleteProperty()方法来取代ES5 Object中delete操作符
2.obj参数必须是对象否则会报错, 若删除成功或删除不存在属性返回true, 否则返回false
let obj = {
a: 1
}
// es5
delete obj.a // true
// es6
Reflect.deleteProperty(obj, 'a') // true
(5)Reflect.construct(target, args)
1.Reflect.construct可以不使用new创建一个对象, 第一个参数必须是函数,否则会报错
function con(name) {
this.name = name
}
// new创建对象写法
let instance = new con('tom')
// Reflect创建对象写法
let instance = Reflect.construct(con, ['tom'])
(6)Reflect.getPrototypeOf(obj)
1.获取对象的原型, obj必须是一个对象,否则会报错,而Object.getPrototypeOf方法如果参数不是对象,会转换成对象再获取obj的原型。
let obj = new Object()
Object.getPrototypeOf(obj) === Object.prototype
Reflect.getPrototypeOf(obj) === Object.prototype
(7)Reflect.setPrototypeOf(obj, newProto)
1.该方法用于设置目标的原型,第一个参数必须是对象,否则会报错,Object.setPrototypeOf方法第一个参数如果不是对象会直接返回该参数。
2.如果传入的第一个参数是null或者undefined则Reflect和Object上的setPrototypeOf方法都会报错。
let a = {}
Object.setPrototypeOf(a, Array.prototype) // 返回对象本身
Reflect.setPrototypeOf(a, Array.prototype) // 返回true
(8)Reflect.apply(func, thisArg, args)
1.该方法相当于Function.prototype.apply(func, thisArg, args),用于绑定this对象执行该函数。
let arr = [1, 2, 3, 4, 5]
// 旧写法
Math.max.apply(Math, arr) // 5
// 新写法
Reflect.apply(Math.max,null , arr) // 5
(9)Reflect.defineProperty(target, propertyKey, attributes)
1.该方法用来为对象定义属性,第一个参数必须是对象否者会报错。 2.该方法可以和Proxy.prototype.defineProperty联合使用
let obj = {}
let handler = {
defineProperty(target, prop, descriptor) {
console.log(descriptor);
return Reflect.defineProperty(target, prop, descriptor);
}
}
let proxy = new Proxy(obj, handler)
proxy.foo = 'bar'
// 给proxy的foo属性赋值会被defineProperty方法拦截
(10)Reflect.getOwnPropertyDescriptor(target, propertyKey)
1.该方法得到指定属性的描述对象
2.该方法取代的是Object.getOwnPropertyDescriptor,如果首个参数不是对象,该方法会报错,而Object.getOwnPropertyDescriptor不报错直接返回undefined,
var obj = {};
Object.defineProperty(obj, 'hidden', {
value: true,
enumerable: false,
});
// 旧写法
var d1 = Object.getOwnPropertyDescriptor(obj, 'hidden')
// 新写法
var d2 = Reflect.getOwnPropertyDescriptor(obj, 'hidden')
(11)Reflect.isExtensible (target)
1.该方法返回一个布尔值,如果对象可以拓展返回true,反之返回false。
2.该方法取代的是Object.isExtensible()方法,他们之间区别是Reflect.isExtensible的参数如果不是对象会报错,Object.isExtensible()参数如果不是对象会返回false
const obj = {}
Object.isExtensible(obj) // true
Reflect.isExtensible(obj) // true
Reflect.preventExtensions(obj)
Object.isExtensible(obj) // false
Reflect.isExtensible(obj) // false
(12)Reflect.preventExtensions(target)
1.该方法使得目标对象不可拓展,传入的参数必须是一个对象否则会报错,它返回一个布尔值,表示是否操作成功。
2.它主要用来取代Object.preventExtensions方法。
let obj = {}
Object.preventExtensions(obj) // 返回冻结的obj对象
Object.preventExtensions(obj) // 返回true
(13)Reflect.ownKeys(target)
1.该方法获得自身的全部属性包括symbol属性相当于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和。
2.该方法参数必须是一个对象否则会报错
let obj = {
a: 1,
b: 2,
[Symbol('c')]: 3,
[Symbol('d')]: 3
}
Object.getOwnPropertyNames(obj) // [a, b]
Object.getOwnPropertySymbols(obj) // [Symbol(c), Symbol(d)]
Reflect.ownKeys(obj)// ["a", "b", Symbol(c), Symbol(d)]
本文参考了阮老师的《ECMAScript 6 入门》