js css htmlES6 新特性

ES6 Reflect

2022-05-09  本文已影响0人  生命里那束光

一、概述

(1) Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在ObjectReflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。

(2) 修改某些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
}

(3) Object操作都变成函数行为。某些Object操作是命令式,比如name in objdelete obj[name],而Reflect.has(obj, name)Reflect.deleteProperty(obj, name)让它们变成了函数行为。

// 老写法
'assign' in Object // true

// 新写法
Reflect.has(Object, 'assign') // true

(4)Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。

例子1:

Proxy(target, {
  set: function(target, name, value, receiver) {
    var success = Reflect.set(target, name, value, receiver);
    if (success) {
      console.log('property ' + name + ' on ' + target + ' set to ' + value);
    }
    return success;
  }
});

上面代码中,Proxy方法拦截target对象的属性赋值行为。它采用Reflect.set方法将值赋值给对象的属性,确保完成原有的行为,然后再部署额外的功能。

例子2:

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对象的拦截操作(getdeletehas),内部都调用对应的Reflect方法,保证原生行为能够正常执行。添加的工作,就是将每一个操作输出一行日志。

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

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

二、静态方法

  • 这些方法的作用,大部分与Object对象的同名方法的作用都是相同的,而且它与Proxy对象的方法是一一对应的。

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

  1. Reflect.get(target, name, receiver):查找并返回target对象的name属性,如果没有该属性,则返回undefined。
  2. Reflect.set(target, name, value, receiver):设置target对象的name属性等于value。
  3. Reflect.has(target, name):对应name in obj里面的in运算符。
  4. Reflect.deleteProperty(target, name):等同于delete obj[name],用于删除对象的属性。
  5. Reflect.ownKeys(target):用于返回对象的所有属性,基本等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和。
  6. Reflect.getOwnPropertyDescriptor(target,name):基本等同于Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象,将来会替代掉后者。
  7. Reflect.defineProperty(target, name,desc):基本等同于Object.defineProperty,用来为对象定义属性。未来,后者会被逐渐废除,请从现在开始就使用Reflect.defineProperty代替它。
  8. Reflect.preventExtensions(target):对应Object.preventExtensions方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功。
  9. Reflect.getPrototypeOf(target):用于读取对象的proto属性,对应Object.getPrototypeOf(obj)。
  10. Reflect.isExtensible(target):对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展。
  11. Reflect.setPrototypeOf(target,prototype):用于设置目标对象的原型(prototype),对应Object.setPrototypeOf(obj, newProto)方法。它返回一个布尔值,表示是否设置成功。
  12. Reflect.apply(target, thisArg, args):等同于Function.prototype.apply.call(func, thisArg, args),用于绑定this对象后执行给定函数。
  13. Reflect.construct(target, args):等同于newtarget(…args),这提供了一种不使用new,来调用构造函数的方法。

三、实例:使用 Proxy 实现观察者模式

观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。

const person = observable({   //数据对象person
  name: '张三',
  age: 20
});

function print() {    //观察者print
  console.log(`${person.name}, ${person.age}`)
}

observe(print);
person.name = '李四';
// 输出
// 李四, 20

上面代码中,数据对象person是观察目标,函数print是观察者。一旦数据对象发生变化,print就会自动执行。

观察者模式实现:

使用 Proxy 写一个观察者模式的最简单实现,即实现observableobserve这两个函数。

思路是observable函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数。

const queuedObservers = new Set();  //先定义了一个Set集合

const observe = fn => queuedObservers.add(fn);  
const observable = obj => new Proxy(obj, {set});  //observable函数返回原始对象的代理

function set(target, key, value, receiver) {
  const result = Reflect.set(target, key, value, receiver);
  queuedObservers.forEach(observer => observer());
  return result;
}

上面代码中,

  1. 先定义了一个Set集合,所有观察者函数都放进这个集合。
  2. 然后,observable函数返回原始对象的代理,拦截赋值操作。
  3. 拦截函数set之中,会自动执行所有观察者。
上一篇下一篇

猜你喜欢

热点阅读