全局对象 Reflect 内置了 JavaScript 元对象协议的所有可拦截操作作为方法。这些方法的名称与处理程序方法的名称相同,正如我们已经看到的,它们有助于将处理程序的操作转发到目标。
Reflect 上的方法可以说 Proxy 上有的它都有,并且也是一样的。这就让 Proxy 对象可以方便地调用对应的 Reflect 方法,完成默认行为,作为修改行为的基础。也就是说,不管 Proxy 怎么修改默认行为,你总可以在Reflect 上获取默认行为。
和其他大多数全局对象不同的是,Reflect 并不是一个构造函数,你不需要使用 new 运算符来构造它的实例。它都是静态方法。
举个例子:
// 老写法
'assign' in Object // true
// 新写法
Reflect.has(Object, 'assign') // true
把一些命令式的写法弄成了函数式的写法,为什么要这样?因为这会使得更加严谨,以及更像一门语言。
我们再那个例子来:
// 老写法
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1
// 新写法
Reflect.apply(Math.floor, undefined, [1.75]) // 1
是不是觉得瞬间清楚了?而原来的写法又臭又长,还要考虑是哪个类型上的方法。
Reflect 静态方法
Reflect 一共有 13 个静态方法,它与 Proxy 一一对应;同时与 Object 上的同名方法也是基本一致的。
(1)Reflect.apply ( target, thisArgument, argumentsList )
概述:静态方法 Reflect.apply() 通过指定的参数列表发起对目标(target)函数的调用。
示例:
Reflect.apply(Math.floor, undefined, [1.75]); // 1
Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]); // "hello"
(2)Reflect.construct ( target, argumentsList [ , newTarget ] )
概述:Reflect.construct 方法等同于 new target(…args),这提供了一种不使用 new,来调用构造函数的方法。
示例:
function Greeting(name) {
this.name = name;
}
// new 的写法
const instance = new Greeting('张三');
// Reflect.construct 的写法
const instance = Reflect.construct(Greeting, '张三');
这样是不是更加是函数式的写法了呢?
(3)Reflect.defineProperty ( target, propertyKey, attributes )
概述:Reflect.defineProperty 方法基本等同于 Object.defineProperty,用来为对象定义属性。未来,后者会被逐渐废除,请从现在开始就使用 Reflect.defineProperty 代替它。
他们也有一点不同,Object.defineProperty 返回一个对象或抛出一个 TypeError 如果属性没有成功被定义。 而 Reflect.defineProperty,只是简单地返回一个 Boolean 是否该属性被成功定义了。
示例:
let o = {};
Reflect.defineProperty(o,'a',{
value: 'name',
writable: true,
enumerable: true,
configurable: true
});
console.log(o); // {a: "name"}
(4)Reflect.deleteProperty ( target, propertyKey )
概述:Reflect.deleteProperty 方法等同于 delete obj[name],用于删除对象的属性。
示例:
const myObj = { foo: 'bar' };
// 旧写法
delete myObj.foo;
// 新写法
Reflect.deleteProperty(myObj, 'foo');
(5)Reflect.get ( target, propertyKey [ , receiver ] )
概述:Reflect.get 方法查找并返回 target 对象的 name 属性,如果没有该属性,则返回 undefined。
示例:
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
}
Reflect.get(myObject, 'foo') // 1
Reflect.get(myObject, 'bar') // 2
Reflect.get(myObject, 'baz') // 3
Reflect.get(myObject, 'a') // undefined
(6)Reflect.getOwnPropertyDescriptor ( target, propertyKey )
概述:Reflect.getOwnPropertyDescriptor 基本等同于 Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象,将来会替代掉后者。
他们之间的不同点在于:如果该方法的第一个参数不是一个对象(一个原始值),那么将造成 TypeError 错误。而对于 Object.getOwnPropertyDescriptor,非对象的第一个参数将被强制转换为一个对象处理。
示例:
Reflect.getOwnPropertyDescriptor("foo", 0);
// TypeError: "foo" is not non-null objectObject.
getOwnPropertyDescriptor("foo", 0);
// { value: "f", writable: false, enumerable: true, configurable: false }
下面的这个方法很奇葩啊,因此我们转而使用第一个方法吧。
(7)Reflect.getPrototypeOf ( target )
概述:Reflect.getPrototypeOf 方法用于读取对象的 [[prototype]] 属性,对应 Object.getPrototypeOf(obj) 方法。
示例:
Reflect.getPrototypeOf({}); // Object.prototype
Reflect.getPrototypeOf(Object.prototype); // null
(8)Reflect.has ( target, propertyKey )
概述:Reflect.has 方法对应
name in obj
里面的 in 运算符。
示例:
let myObject = { foo: 1,};
// 旧写法
'foo' in myObject; // true
// 新写法
Reflect.has(myObject, 'foo'); // true
(9)Reflect.isExtensible ( target )
概述:Reflect.isExtensible 方法对应 Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展。
示例:
const myObject = {};
// 旧写法
Object.isExtensible(myObject); // true
// 新写法
Reflect.isExtensible(myObject); // true
(10)Reflect.ownKeys ( target )
概述:Reflect.ownKeys 方法用于返回对象的所有属性,基本等同于 Object.getOwnPropertyNames 与Object.getOwnPropertySymbols 之和。
示例:
var myObject = {
foo: 1,
bar: 2,
[Symbol.for('baz')]: 3,
[Symbol.for('bing')]: 4,
};
// 旧写法
Object.getOwnPropertyNames(myObject); // ['foo', 'bar']
Object.getOwnPropertySymbols(myObject); //[Symbol.for('baz'), Symbol.for('bing')]
// 新写法
Reflect.ownKeys(myObject); // ['foo', 'bar', Symbol.for('baz'), Symbol.for('bing')]
(11)Reflect.preventExtensions ( target )
概述:Reflect.preventExtensions 对应 Object.preventExtensions 方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功。
示例:
var myObject = {};
// 旧写法
Object.preventExtensions(myObject); // {}
// 新写法
Reflect.preventExtensions(myObject); // true
(12)Reflect.set ( 8target, propertyKey, V [ , receiver ]* )
概述:Reflect.set 方法设置 target 对象的 name 属性等于 value。
示例:
let myObject = {
a: 1
};
console.log(myObject.a); // 1
Reflect.set(myObject,'a',2);
console.log(myObject.a); // 2
(13)Reflect.setPrototypeOf ( target, proto )
概述:Reflect.setPrototypeOf 方法用于设置对象的 [[prototype]]属性,对应 Object.setPrototypeOf(obj, newProto)。
示例:
const myObj = new FancyThing();
// 旧写法
Object.setPrototypeOf(myObj, Other.prototype);
// 新写法
Reflect.setPrototypeOf(myObj, Other.prototype);
至此,Reflect 上的方法我已经全部讲完了。所以我也不需要再回头再将 Proxy 上的方法了吧?都是一模一样的。
未来我们将 Object 上的类似方法全部替换成这里所讲的 13 个方法,就是我们学习这一节的主要目的。
总结
好啦,我们的 ECMAScript 之旅到此结束啦。虽然舍不得,不过我写下这 5 万多字如果给你带来了任何帮助,不妨给我点点的支持,一个 ❤ 或一个关注都可以啦。
接下来,我们要进行 CSS3 之旅啦。同样的,我将会详细地介绍 CSS3 以及之前版本中所有的属性以及它的使用方法。
我个人的行事风格就是 —— 我将我所有的东西都交给你,而你只需要取你需要的那一部分。