概述
Reflect
对象是一个全局的普通的对象。Reflect
的原型就是 Object
。
我们来验证下 Reflect
的原型是否是 Object
, 代码如下:
const obj = {}
console.log(Reflect.__proto__ === Object.prototype); // true
console.log(Reflect.__proto__ === obj.__proto__);
Reflect
是 ES6 为了操作对象而新增的 API
,Reflect
对象的设计目的有这样几个。
1) 将 Object
对象的一些明显属于语言内部的方法(比如 Object.defineProperty
)放到Reflect
对象上。现阶段,某些方法同时在Object
和 Reflect
对象上部署,未来的新方法将只部署在 Reflect
对象上。也就是说,从 Reflect
对象上可以拿到语言内部的方法。
2)使用对象 Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而 Reflect.defineProperty(obj, name, desc)
则会返回 false
。
// 老写法
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
}
// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
3)有了 Reflect
对象以后,很多操作会更易读。
// 老写法
Function.prototype.apply.call(Math.floor, undefined, [1.22]) // 1
// 新写法
Reflect.apply(Math.floor, undefined, [1.22]) // 1
静态方法
Reflect
对象一共有 13 个静态方法。
Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
Reflect.get(target, name, receiver)
参数解析
- target:目标对象。
- name:要读取的属性。
- receiver:上下文
this
对象(可选)
Reflect.get
方法查找返回 target
对象的 name
属性,如果没有该属性,则返回 undefined
const person = {
name: "张三",
age: 18,
get habby() {
return this.name + this.age + "岁"
}
};
Reflect.get(person, "name"); // 张三
Reflect.get(person, "age"); // 18
Reflect.get(person, "habby"); // 张三18岁
如果 name
属性部署了读取函数 getter
,则读取函数的 this
绑定 receiver
。
const person = {
name: "李四",
age: 20,
get habby() {
return this.name + this.age + "岁";
}
}
const person1 = {
name: "王五",
age: 30
}
Reflect.get(person, "habby", person1); // 王五30岁
如果第一个参数不是对象,Reflect.get
方法会报错
Reflect.get(1, "habby"); // 报错
Reflect.get(false, "habby"); // 报错
Reflect.set(target, name, value, receiver)
参数解析
- target:目标对象。
- name:要读取的属性。
- value:要设置的属性值。
- receiver:上下文
this
指向。
Reflect.set
方法设置 target
对象的 name
属性等于 value
。
const person = {
name: "张三",
set habby(value) {
return this.name = value;
}
};
person.name; // 张三
Reflect.set(person, "name", "李四");
person.name; // 李四
Reflect.set(person, "habby", "王五");
person.habby; // 王五
如果 name
属性设置了赋值函数,则赋值函数的 this
绑定 receiver
。
const person = {
name: "张三",
set habby(value) {
return this.name = value;
}
};
const person1 = {
name: "李四"
};
Reflect.set(person, "name", "王五", person1);
person.name; // 张三
person1.name; // 王五
注意,如果 Proxy
对象和 Reflect
对象联合使用,前者拦截赋值操作,后者完成赋值的默认行为,而且传入了 receiver
,那么 Reflect.set
会触发 Proxy.defineProperty
拦截。
const perosn = {
name: "张三"
};
const proxy = new Proxy(perosn, {
set(target, key, value, receiver) {
console.log('set');
Reflect.set(target, key, value, receiver)
},
defineProperty(target, key, attribute) {
console.log('defineProperty');
Reflect.defineProperty(target, key, attribute);
}
});
person.name = "王五";
// set
// defineProperty
上面代码中,Proxy.set
拦截里面使用了 Reflect.set
,而且传入了 receiver
,导致触发Proxy.defineProperty
拦截。这是因为 Proxy.set
的 receiver
参数总是指向当前的 Proxy
实例(即上例的obj),而 Reflect.set
一旦传入 receiver
,就会将属性赋值到 receiver
上面(即 obj
),导致触发 defineProperty
拦截。如果 Reflect.set
没有传入 receiver
,那么就不会触发 defineProperty
拦截。
const person = {
name: "张三"
};
const proxy = new Proxy(perosn, {
set(target, key, value, receiver) {
console.log('set');
Reflect.set(target, key, value)
},
defineProperty(target, key, attribute) {
console.log('defineProperty');
Reflect.defineProperty(target, key, attribute);
}
});
person.name = "王五";
// set
如果第一个参数不是对象,Reflect.set
会报错。
Reflect.set(1, "name", {}); // 报错
Reflect.set(false, "name", {}); // 报错
Reflect.has(obj, name)
参数解析
- obj:目标对象
- name:对象中的
key
值
Reflect.has
方法对应 name in obj
里面的 in
运算符
const person = {
name: "张三",
age: 20
};
"name" in person; // true
Reflect.has(person, "name") // true
Reflect.deleteProperty(obj, name)
参数解析:
- obj:目标对象
- name:对象中的
key
值
Reflect.deleteProperty
方法等同于 delete obj[name]
,用于删除对象的属性。
const person = {
name: "张三",
age: 20
};
delete person.age // 旧写法
Reflect.deleteProperty(person, "age"); // 新写法
该方法返回一个布尔值。如果删除成功,或者被删除的属性不存在,返回 true
;删除失败,被删除的属性依然存在,返回 false
。
如果 Reflect.deleteProperty()
方法的第一个参数不是对象,会报错。
Reflect.construct(target, args)
参数解析
- target:函数对象
- args:构造函数参数对象
Reflect.construct
方法等同于 new target(...args)
,这是一种不使用 new
,来调用构造函数的方法。
function Person(name) {
this.name = name;
}
const instance = new Person("张三"); // new 的写法
const instance = Reflect.construct(Person, ["张三"]) // Reflect.construct 的写法
如果 Reflect.construct()
方法的第一个参数不是函数,会报错。
Reflect.getPrototypeOf(obj)
参数解析
- obj:要读取的对象。
Reflect.getPrototypeOf
方法用于读取对象的 __proto__
属性,对应 Object.getPrototypeOf(obj)
。
const person = new Person();
// 旧写法
Object.getPrototypeOf(person) === person.prototype;
// 新写法
Reflect.getPrototypeOf(person) === person.prototype;
Reflect.getPrototypeOf
和 Object.getPrototypeOf
的一个区别是,如果参数不是对象,Object.getPrototypeOf
会将这个参数转为对象,然后再运行,而 Reflect.getPrototypeOf
会报错。
Object.getPrototypeOf(1) // Number {[[PrimitiveValue]]: 0}
Reflect.getPrototypeOf(1) // 报错
Reflect.setPrototypeOf(obj, newProto)
参数解析
- obj:目标对象。
- newProto:要设置的原型。
Reflect.setPrototypeOf
方法用于设置目标对象的原型(prototype
),对应 Object.setPrototypeOf(obj, newProto)
方法。它返回一个布尔值,表示是否设置成功。
const person = {};
Object.setPrototypeOf(person, Array.prototype); // 旧写法
Reflect.setPrototypeOf(person, Array.prototype); // 新写法
如果无法设置目标对象的原型(比如,目标对象禁止扩展),Reflect.setPrototypeOf
方法返回 false
。
Reflect.setPrototypeOf({}, null); // true
Reflect.setPrototypeOf(Object.freeze({}), null); // false
如果第一个参数不是对象,Object.setPrototypeOf
会返回第一个参数本身,而 Reflect.setPrototypeOf
会报错。
Object.setPrototypeOf(1, {}); // 1
Reflect.setPrototypeOf(1, {}); // TypeError: Reflect.setPrototypeOf called on non-object
如果第一个参数是 undefined
或 null
,Object.setPrototypeOf
和 Reflect.setPrototypeOf
都会报错。
Object.setPrototypeOf(null, {}); // TypeError: Object.setPrototypeOf called on null or undefined
Reflect.setPrototypeOf(null, {}); // TypeError: Reflect.setPrototypeOf called on non-object
Reflect.apply(func, thisArg, args)
参数解析
- func:目标函数
- thisArg:
func
函数调用的时候绑定的this
对象。 - args:函数的参数列表
Reflect.apply
方法等同于 Function.prototype.apply.call(func, thisArg, args)
,用于绑定 this
对象后执行给定函数。
一般来说,如果要绑定一个函数的 this
对象,可以这样写 fn.apply(obj, args)
,但是如果函数定义了自己的 apply
方法,就只能写成 Function.prototype.apply.call(fn, obj, args)
,采用 Reflect
对象可以简化这种操作。
const ages = [1, 2, 3, 4];
// 旧写法
const min = Math.min.apply(Math, ages);
const max = Math.max.apply(Math, ages);
const type = Object.prototype.toString.call(min);
// 新写法
const min = Reflect.apply(Math.min, Math, ages);
const max = Reflect.apply(Math.max, Math, ages);
const type = Reflect.apply(Object.prototype.toString, youngest, []);
Reflect.defineProperty(target, propertyKey, attributes)
参数解析
- target:目标对象。
- propertyKey:目标对象
key
值。 - attributes:目标对象
value
值。
Reflect.defineProperty
方法基本等同于 Object.defineProperty
,用来为对象定义属性。未来,后者会被逐渐废除,请从现在开始就使用 Reflect.defineProperty
代替它。
function MyDate() {}
// 旧写法
Object.defineProperty(MyDate, "now", {
value: () => Date.now()
});
// 新写法
Reflect.defineProperty(MyDate, "now", {
value: () => Date.now()
});
如果 Reflect.defineProperty
的第一个参数不是对象,就会抛出错误,比如
Reflect.defineProperty(1, "name")
这个方法可以与 Proxy.defineProperty
配合使用。
const proxy = new Proxy({}, {
defineProperty(target, prop, descriptor) {
console.log(descriptor);
return Reflect.defineProperty(target, prop, descriptor);
}
});
proxy.name = "张三";
// { value: "张三", writable: true, enumerable: true, configurable: true }
proxy.name // "张三"
Reflect.getOwnPropertyDescriptor(target, propertyKey)
参数解析
- target:目标对象
- propertyKey:目标对象属性值
Reflect.getOwnPropertyDescriptor
基本等同于 Object.getOwnPropertyDescriptor
,用于得到指定属性的描述对象,将来会替代掉后者。
const person = {};
Object.defineProperty(person, "name", {
value: true,
enumerable: false
});
// 旧写法
var theDescriptor = Object.getOwnPropertyDescriptor(person, "name");
// 新写法
var theDescriptor = Reflect.getOwnPropertyDescriptor(person, "name");
Reflect.getOwnPropertyDescriptor
和 Object.getOwnPropertyDescriptor
的一个区别是,如果第一个参数不是对象,Object.getOwnPropertyDescriptor(1, "name")
不报错,返回 undefined
,而 Reflect.getOwnPropertyDescriptor(1, "name")
会抛出错误,表示参数非法。
Reflect.isExtensible (target)
参数解析
- target:目标对象
Reflect.isExtensible
方法对应 Object.isExtensible
,返回一个布尔值,表示当前对象是否可扩展。
const person = {};
// 旧写法
Object.isExtensible(person) // true
// 新写法
Reflect.isExtensible(person) // true
如果参数不是对象,Object.isExtensible
会返回 false
,因为非对象本来就是不可扩展的,而Reflect.isExtensible
会报错。
Object.isExtensible(1) // false
Reflect.isExtensible(1) // 报错
Reflect.preventExtensions(target)
参数解析
- target:目标函数。
Reflect.preventExtensions
对应 Object.preventExtensions
方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功。
var person = {};
// 旧写法
Object.preventExtensions(person ) // Object {}
// 新写法
Reflect.preventExtensions(myObject) // true
如果参数不是对象,Object.preventExtensions
在 ES5 环境报错,在 ES6 环境返回传入的参数,而Reflect.preventExtensions
会报错。
// ES5 环境
Object.preventExtensions(1) // 报错
// ES6 环境
Object.preventExtensions(1) // 1
// 新写法
Reflect.preventExtensions(1) // 报错
Reflect.ownKeys (target)
参数解析
- target:目标对象。
Reflect.ownKeys
方法用于返回对象的所有属性,基本等同于 Object.getOwnPropertyNames
与 Object.getOwnPropertySymbols
之和。
const person = {
foo: 1,
bar: 2,
[Symbol.for('baz')]: 3,
[Symbol.for('bing')]: 4,
};
// 旧写法
Object.getOwnPropertyNames(person)
// ['foo', 'bar']
Object.getOwnPropertySymbols(person)
//[Symbol(baz), Symbol(bing)]
// 新写法
Reflect.ownKeys(person)
// ['foo', 'bar', Symbol(baz), Symbol(bing)]
如果 Reflect.ownKeys()
方法的第一个参数不是对象,会报错。