Reflect
什么是反射
在计算机编程中,反射是指程序在运行时能够操作变量、属性和对象的方法。
在 ES6 之前,JavaScript 已经具备反射功能,尽管这些功能当时未被社区或规范正式称为“反射”。例如 Object.keys()、Object.getOwnPropertyDescriptor()和 Array.isArray()等方法就是经典的反射功能。
ES6 引入了一个全新的全局对象,名为 Reflect,它允许你调用方法、构造对象、获取和设置属性,以及操作和扩展属性。它允许你开发能够处理动态代码的程序和框架。
Reflect 设计目的
将
Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。修改某些
Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
try {
Object.defineProperty({}, "name", { value: "coderlzw", writable: trujavase, enumerable: true, configurable: true });
// success
} catch (error) {
// failure
}if (Reflect.defineProperty({}, "name", { value: "coderlzw", writable: true, enumerable: true, configurable: true })) {
// success
} else {
// failure
}让
Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
const peron = { name: "coderlzw", age: 20 };
const result = 'name' in peron
console.log(result); // 输出: trueconst peron = { name: "coderlzw", age: 20 };
const result = Reflect.has(perons, "name");
console.log(result); // 输出: trueReflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
上面代码中,Proxy方法拦截target对象的属性赋值行为。使用 Reflect.set 方法将至赋给对象的属性,确保完成原有的行为,然后在部署额外的功能javas
上面代码中,每个Proxy对象的拦截拦截操作,内部都调用对应的 Reflect 方法,保证原生行为能够正常执行。添加的工作,就是将每一个操作输出一行日志。
静态方法
Reflect.apply(target, thisArg, args)
Reflect.apply 方法等同于 Function.prototype.apply.call(func, thisArg, args),用于绑定 this 对象后执行给定函数。
一般来说,如果要绑定一个函数的 this 对象,可以写成这样 fn.apply(context, args),但是如果函数定义了自己的 apply 方法,就只能写成 Function.prototype.apply.call(fn, context, args),采用 Reflect 对象可以简化这种操作。
Reflect.construct(target, args)
Reflect.construct方法等同于new target(...args),这提供了一种不使用new,来调用构造函数的方法。
如果Reflect.construct()方法的第一个参数不是函数,会报错。
Reflect.get(target, name, receiver)
Reflect.get方法查找并返回target对象的name属性,如果没有该属性,则返回undefined。
如果 name 属性部署了 getter,则 getter 函数的 this 绑定 receiver
Reflect.set(target, name, value, receiver)
Reflect.set 方法设置 target 对象的 name 属性等于 value。
如果 name 属性设置了赋值函数,则赋值函数的 this 绑定 receiver。
如果 Proxy 对象和 Reflect 对象联合使用,前者拦截赋值操作,后者完成赋值的默认行为。而传入了 receiver,那么 Reflect.set 会触发 Proxy.defineProperty 拦截。
上面的示例中,Proxy 拦截里面使用了 Reflect.set 方法,并传入了 receiver,导致触发 Proxy.defineProperty 拦截。这是因为 Proxy.set 的 receiver 参数总是指向当前的 Proxy 实例(即将 proxy),而 Reflect.set 的一旦传入 receiver,就会将属性赋值到 receiver 上(即 proxy),导致触发 Proxy.defineProperty 拦截。
如果 Reflect.set 方法没有传入 receiver,那么就不会触发 defineProperty 拦截。
Reflect.defineProperty(target, name, desc)
Reflect.defineProperty方法基本等同于Object.defineProperty,用来为对象定义属性。未来,后者会被逐渐废除,请从现在开始就使用Reflect.defineProperty代替它。
如果Reflect.defineProperty的第一个参数不是对象,就会抛出错误,比如Reflect.defineProperty(1, 'foo')。
这个方法可以与Proxy.defineProperty配合使用。
上面代码中,Proxy.defineProperty对属性赋值设置了拦截,然后使用Reflect.defineProperty完成了赋值。
Reflect.deleteProperty(target, name)
Reflect.deleteProperty方法等同于delete obj[name],用于删除对象的属性。
该方法返回一个布尔值。如果删除成功,或者被删除的属性不存在,返回true;删除失败,被删除的属性依然存在,返回false。
如果Reflect.deleteProperty()方法的第一个参数不是对象,会报错。
Reflect.has(target, name)
Reflect.has方法对应name in obj里面的in运算符。
Reflect.ownKeys(target)
Reflect.ownKeys 方法返回对象的所有属性,等同于 Object.getOwnPropertyNames 与 Object.getOwnPropertySymbols 之和。
Reflect.isExtensible(target)
Reflect.isExtensible 方法对应 Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展。
如果参数不是对象,Object.isExtensible 会返回 false,而 Reflect.isExtensible 会抛出错误。
Reflect.preventExtensions(target)
Reflect.preventExtensions 方法对应 Object.preventExtensions 方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功。
如果参数不是对象,Object.preventExtensions 在 ES5 环境报错,在 ES6 环境返回传入的参数,而 Reflect.preventExtensions 会报错。
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getOwnPropertyDescriptor 基本等同于 Object.getOwnPropertyDescriptor,用于获取指定属性的描述对象。
如果参数不是对象,Object.getOwnPropertyDescriptor返回 undefined,而 Reflect.getOwnPropertyDescriptor 会抛出错误。
Reflect.getPrototypeOf(target)
Reflect.getPrototypeOf方法用于读取对象的__proto__属性,对应Object.getPrototypeOf(obj)。
Reflect.getPrototypeOf和Object.getPrototypeOf的一个区别是,如果参数不是对象,Object.getPrototypeOf会将这个参数转为对象,然后再运行,而Reflect.getPrototypeOf会报错。
Reflect.setPrototypeOf(target, prototype)
Reflect.setPrototypeOf方法用于设置目标对象的原型(prototype),对应Object.setPrototypeOf(obj, newProto)方法。它返回一个布尔值,表示是否设置成功。
如果无法设置目标对象的原型(比如,目标对象禁止扩展),Reflect.setPrototypeOf方法返回false。
如果第一个参数不是对象,Object.setPrototypeOf会返回第一个参数本身,而Reflect.setPrototypeOf会报错。
如果第一个参数是undefined或null,Object.setPrototypeOf和Reflect.setPrototypeOf都会报错。
最后更新于
这有帮助吗?