ES6学习12 Reflect

此文参考学习于 阮一峰老师《ES6入门》,更多特性以及方法可以点击查看

1.概述

Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。

2.设计目的

  1. 将 Object 对象语言内部的方法,放到 Reflect 对象上。

现阶段,某些方法同时在 Object 和 Reflect 对象上部署。也就是说,很多方法你可以通过 Object 调用,也可以通过
Rflect 来调用。但是这只限制于现在已有的方法,未来的新方法将只部署在Reflect对象上。

  1. 修改某些 Object 方法的返回结果,让其变得更合理。
    比如,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
}
  1. 让 Object 操作都变成函数行为。举个典型的例子,in 操作符
// 老写法
'assign' in Object // true

// 新写法
Reflect.has(Object, 'assign') // true
  1. 使得Reflect 对象的方法与Proxy 对象的方法一一对应。这就让 Proxy 对象可以方便地调用对应的 Reflect 方法。
    之前的学习中也例出过 Proxy对象的方法,学习完本章,你会发现每一个Reflect 对象的方法和 Proxy 对象的方法一一对应。这就让 Proxy 对象可以方便地调用对应的 Reflect 方法,完成默认行为
    也就是说,不管 Proxy 怎么修改默认行为,你总可以在 Reflect 上获取默认行为。

举个例子

var loggedObj = new Proxy(obj, {
  get(target, name) {
    console.log('get', target, name);
    return Reflect.get(target, name);
  },
  deleteProperty(target, name) {
    console.log('delete' + name);
    return Reflect.deleteProperty(target, name);
  },
  has(target, name) {
    console.log('has' + name);
    return Reflect.has(target, name);
  }
});

上面代码中,每一个Proxy对象的拦截操作(get、delete、has),内部都调用对应的Reflect方法,保证原生行为能够正常执行。添加的工作,就是将每一个操作输出一行日志。

  1. 有了 Reflect 对象以后,很多操作会更易读。
// 老写法
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1

// 新写法
Reflect.apply(Math.floor, undefined, [1.75]) // 1

3.静态方法

Reflec t对象一共有 13 个静态方法。

  • Reflect.apply(target, thisArg, args) 改变 target 中的 this 指向,执行函数,并传参。
    -一般来说,如果要绑定一个函数的this对象,可以这样写 function.apply(obj, args),但是如果函数定义了自己的apply方法,就只能写成Function.prototype.apply.call(fn, obj, args),采用Reflect对象可以简化这种操作。

  • Reflect.construct(target, args) 等同于new target(…args),可以代替 new 来调用(实例化)构造函数,第一个参数必须是函数,否则报错。

function Greeting(name) {
  this.name = name;
}

// new 的写法
const instance = new Greeting('张三');

// Reflect.construct 的写法
const instance = Reflect.construct(Greeting, ['张三']);
  • Reflect.get(target, name, receiver) 找到 target 中的 name ,如果 name属性部署了读取函数(getter),则读取函数的this绑定receiver。返回一个与 name 对应的键值,若无对应属性,则返回 undefined。

  • Reflect.set(target, name, value, receiver) 设置 target 中的 键值对(name,value)。如果name属性设置了赋值函数,则赋值函数的this绑定receiver。

  • Reflect.defineProperty(target, name, desc) 基本等同于Object.defineProperty。用来为对象本身定义属性。后者会被逐渐废除,请从现在开始就使用Reflect.defineProperty代替它。
    desc 参数用来定义 name( 属性 )的描述对象。

  • Reflect.deleteProperty(target, name)等同于delete obj[name],用于删除 target 上的 name(属性)。如果删除成功,或者被删除的属性不存在,返回 true;删除失败,被删除的属性依然存在,返回 false。第一个参数必须是对象,否则报错。

  • Reflect.has(target, name) 返回一个 Boolean 值,检查 target 中的 name(属性)是否存在(has 方法对应name in obj里面的in运算符。)

  • Reflect.ownKeys(target)方法用于返回对象的所有属性名(包括 Symbol 类型),基本等同于 Object.getOwnPropertyNames 与 Object.getOwnPropertySymbols 之和。返回一个数组

  • Reflect.isExtensible(target) 对应Object.preventExtensions方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功。

  • Reflect.preventExtensions(target)对应Object.isExtensible,返回一个布尔值,表示 target(当前对象)是否可扩展。

  • Reflect.getOwnPropertyDescriptor(target, name)基本等同于Object.getOwnPropertyDescriptor,用于 得到 指定属性的描述对象,将来会替代掉后者。

  • Reflect.getPrototypeOf(target)用于读取对象的__proto__属性``。Reflect.getPrototypeOfObject.getPrototypeOf的一个区别是,如果参数不是对象,后者会将这个参数转为对象,然后再运行,而前者会报错。

  • Reflect.setPrototypeOf(target,prototype)用于设置目标对象的原型。它返回一个布尔值,表示是否设置成功。第一个参数必须为对象。第二个参数要为一个对象,若为一个函数,则会影响成为 target 为一个函数

方法详细实例介绍请点击阮一峰《ESMAScript 6 入门》文档

4.使用Proxy 实现观察者模式

观察者模式指的是定义函数来观察对象,一旦对象中发生变化,函数就会自动执行

const callbacks = new Set();   // 初始化 回调
const observe = fn => callbacks.add(fn); // 声明观察容器
const observable = obj => new Proxy(obj, {set});  //定义 proxy 代理

function set (target, key, value, receiver) { 
    const result = Reflect.set(target, key, value, receiver);
    callbacks.forEach(observe => observe()); //遍历执行回调函数,打印变量
    return result;
}
//  一个可观察的对象
const person = observable({name: 'liu', age: 18}); // 定义观察目标

function change() {
    console.log(`${person.name} is ${person.age}`);
}


observe(change);

person.age = 19;
}
  • 首先定义了一个observe 用来存储 要触发的函数。
  • 然后定义了一个observable 函数 对 对象的设值做了一层代理,拦截赋值操作, Reflect.set用来完成默认的设值行为,
    然后触发函数。
  • 每当对象调用对象内部的的set方法时,就会遍历触发我们添加进callbacks里的回调函数。 打印结果:当age发生变化时:函数执行,打印变量

看明白上面的代码后,对观察者模式有了全新的认识,同时我也很疑惑。
一开始看官方文档,简单易懂,认为观察者模式是ES6定义好了的可以直接使用的自带功能。
但是上面的代码按这个道理说应该输出两次,但是并没有。所以说,观察者模式的主要实现还是靠 Proxy代理的 set方法来完成。
也不知道理解得对不对,大家可以试一试,有知道的大佬欢迎留言指点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值