元程序设计之 Reflect(映射)

全局对象 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 以及之前版本中所有的属性以及它的使用方法。

我个人的行事风格就是 —— 我将我所有的东西都交给你,而你只需要取你需要的那一部分。

    原文作者:Hushaby丶
    原文地址: https://www.jianshu.com/p/3f66e34b7bd5
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞