Reflect与Object比较

开始进入到Vue.js框架的深层原理学习和实现,在此之前,有一些基本概念要认识下。根据当前个人的认知,目前双向绑定的主要实现方式有观察者模式和劫持方式。说到劫持的方式,主要就是通过Object.definedProperty(...)来覆盖get/set方法来达到劫持的目的。
而在ES6,新提供了一个内置对象Reflect,同样可以达到Object的作用。那么我们来看看它们之间的区别。

定义

Reflect is a built-in object that provides methods for interceptable JavaScript operations. The methods are the same as those of proxy handlers. Reflect is not a function object, so it’s not constructible.

根据MDN上对Reflect的定义,它的核心是interceptable JavaScript operations,也就是拦截操作,而Object的定义是创建对象的包装器。

另外,ES6更提供了一个Proxy内置对象,所含方法和Reflect基本一致,主要区别在于,使用Proxy后返回的是一个包装好的Proxy类,继承于传入的Object,而Reflect则是直接操作原有的Object.
那么我们如果要劫持多个对象的话,Proxy是更好的选择。

另外我们常年会使用Object.definedProperty(...)来做劫持相关的操作,但是根据阮一峰ES6 - Reflect中描述,未来的新方法将只部署在Reflect对象上。也就是说, 现在如果是劫持相关的操作,替换使用Reflect是比较好的选择。

方法

Reflect对象提供以下静态函数,它们具有与处理器对象方法相同的名称。这些方法中的一些与 Object 上的对应方法相同。

  • Reflect.apply()
    对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。
  • Reflect.construct()
    对构造函数进行 new 操作,相当于执行 new target(…args)。
  • Reflect.defineProperty()
    和 Object.defineProperty() 类似。
  • Reflect.deleteProperty()
    作为函数的delete操作符,相当于执行 delete target[name]。
  • Reflect.enumerate()
    该方法会返回一个包含有目标对象身上所有可枚举的自身字符串属性以及继承字符串属性的迭代器,for…in 操作遍历到的正是这些属性。
  • Reflect.get()
    获取对象身上某个属性的值,类似于 target[name]。
  • Reflect.getOwnPropertyDescriptor()
    类似于 Object.getOwnPropertyDescriptor()。
  • Reflect.getPrototypeOf()
    类似于 Object.getPrototypeOf()。
  • Reflect.has()
    判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
  • Reflect.isExtensible()
    类似于 Object.isExtensible().
  • Reflect.ownKeys()
    返回一个包含所有自身属性(不包含继承属性)的数组。
  • Reflect.preventExtensions()
    类似于 Object.preventExtensions()。返回一个Boolean。
  • Reflect.set()
    将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
  • Reflect.setPrototypeOf()
    类似于 Object.setPrototypeOf()。

可以看到,绝大部分的劫持方法都提供好了,可以看到,例如,我们要判断一个对象是否存在某个属性的时候,以往的做法是:

1
2
3
if ('test' in Obj) {
// 存在
}

使用了in运算符,为了更规范的函数化编程,可以使用:

1
2
3
if (Reflect.has(Obj,'test')) {
// 存在
}

因此可以看到Reflect存在的一部分原因就是为了把原来JavaScript中存在的命令式操作改成使用它的函数操作。

因为大部分方法的意义跟Object一样,这里不再详细诉述,可以去查看阮老师的文章。

异常处理

最大的区别在于对异常的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 老写法
try {
Object.defineProperty(target, property, attributes);
// success
} catch (e) {
// failure
}

// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}

就是说,不需要经过try/catch来处理异常,看个人喜好了。