ES6的Reflect对象详解

1,289 阅读4分钟

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 入门》