简介

Reflect对象与Proxy对象一样,也是ES6为了操作对象而提供的新API。
Reflect对象是一个全局的普通的对象。Reflect的原型就是Object.

  1. let obj = {};
  2. console.log(Reflect.__proto__ === Object.prototype); // true
  3. console.log(obj.__proto__ === Reflect.__proto__); // true

设计目的

  • 将Object对象的一些明显属于语言内部的方法,放到Reflect对象上,未来的新方法只放在Reflect对象上。
  • 修改Object的一些方法,让其变得更合理。让Object操作都变成函数行为。
  • Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy上的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect对象上的函数,完成默认行为。也就是说,不管Proxy对象怎么修改默认行为,总可以在Reflect对象上获取默认行为。 ```javascript // 传统写法 ‘assign’ in Object // true

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

// 传统写法 try { // 如果一个对象不能扩展,那么在调用Object.defineProperty(obj, name, desc)时,会抛出一个异常 Object.defineProperty(target, property, attributes); } catch (e) { // failure }

// 新写法 if (Reflect.defineProperty(target, property, attributes)) { // 使用Reflect.defineProperty()时,返回的是布尔值 } else { // failure }

  1. ```javascript
  2. // 在Proxy里调用Reflect对象的方法
  3. let target = {
  4. name: 'kingx'
  5. };
  6. const proxy = new Proxy(target, {
  7. get(target, prop) {
  8. console.log(`读取属性${prop}的值为${target[prop]}`);
  9. return Reflect.get(target, prop);
  10. },
  11. set(target, prop, value) {
  12. console.log(`设置属性${prop}的值为${value}`);
  13. return Reflect.set(target, prop, value);
  14. },
  15. deleteProperty(target, prop) {
  16. console.log('删除属性: ' + prop);
  17. return Reflect.deleteProperty(target, prop);
  18. }
  19. });
  20. proxy.name; // 读取属性name的值为'kingx'
  21. proxy.name = 'kingx2'; // 设置属性name的值为'kingx2'
  22. delete proxy.name; // 删除属性: name

Proxy、Reflect二者配合使用,实现观察者模式:
观察者模式:一个目标对象管理所有依赖于它的观察者对象,当自身的状态有变更时,会主动向所有观察者发出通知。
Proxy的set()函数实现拦截,Reflect的set()函数用于设置值

  1. // 目标对象
  2. const target = {
  3. name: 'kingx'
  4. };
  5. // 观察者队列,包含所有的观察者对象
  6. const queueObservers = new Set();
  7. // 第一个观察者对象
  8. function observer1(prop, value) {
  9. console.log(`目标对象的${prop}属性值变为${value},观察者1开心地笑了`);
  10. }
  11. // 第二个观察者对象
  12. function observer2(prop, value) {
  13. console.log(`目标对象的${prop}属性值变为${value},观察者2伤心地哭了`);
  14. }
  15. // 为目标对象添加观察者
  16. const observer = (fn) => queueObservers.add(fn);
  17. observer(observer1);
  18. observer(observer2);
  19. // Proxy的set()函数,用于拦截目标对象属性修改的操作
  20. function set(target, prop, value) {
  21. // 使用Reflect.set()函数修改属性
  22. const result = Reect.set(target, prop, value);
  23. // 执行通知函数,通知所有的观察者
  24. result ? queueObservers.forEach(fn => fn(prop, value)) : '';
  25. return result;
  26. }
  27. // 通过Proxy生成目标对象的代理的函数
  28. const observable = (target) => new Proxy(target, {set});
  29. // 获取代理
  30. const proxy = observable(target);
  31. proxy.name = 'kingx2';

Reflect静态函数

Reflect对象本身并不是一个构造函数,而是直接提供静态函数以供调用,Reflect对象的静态函数一共有13个

Reflect.get()

**Reflect.get(target, propKey, receiver)**用来读取一个对象的属性值,等同于执行target[propKey]
target: 目标对象
propKey: 要读取的属性。
receiver(可选): 可以理解为上下文this对象。

  1. const obj = {
  2. name: 'kongzhi',
  3. age: 30,
  4. get test() {
  5. console.log(this.name);
  6. console.log('-------');
  7. },
  8. get test2() {
  9. console.log(this.name);
  10. console.log('----xxxx---');
  11. return 0;
  12. }
  13. };
  14. console.log(Reflect.get(obj, 'name')); // kongzhi
  15. console.log(Reflect.get(obj, 'yyy')); // undefined
  16. /*
  17. 先执行 test 方法 打印 kongzhi 和 ----,
  18. 然后在打印undefined, 因为该test()函数没有返回值
  19. */
  20. console.log(Reflect.get(obj, 'test'));
  21. /*
  22. 会执行 test() 方法,打印 happy, 因此第三个参数指向上下文
  23. 就指向了这个对象,然后打印 ----- ,最后打印undefined
  24. 因为该函数没有返回值
  25. */
  26. console.log(Reflect.get(obj, 'test', {name: 'happy'}));
  27. /*
  28. 会执行 test() 方法, 指定了第三个参数作为该上下文对象,而这个对象里面又没有name属性,因此会打印undefined,然后打印 ----- ,最后打印undefined.
  29. */
  30. console.log(Reflect.get(obj, 'test', {age: 'happy'}));
  31. /*
  32. 会执行 test2() 方法,指定了第三个参数作为该上下文对象,
  33. 因此会打印 happy2, 然后继续打印 ----xxxx---, 最后有返回值为0,因此打印0了
  34. */
  35. console.log(Reflect.get(obj, 'test2', {name: 'happy2'}));

Reflect.set()

**Reflect.set(target, propKey, value, receiver)**函数是设置某个属性值,等同于执行target[propKey] = value。该函数会返回一个Boolean的值,代表在目标对象上设置属性是否成功。
target: 需要操作的目标对象。
name: 需要设置该对象的属性名。
value: 要设置的属性值。
receiver(可选): 可以理解为上下文this对象。如果在设置值的时候遇到setter函数,该参数就指向与setter中上下文this对象。

  1. const obj = {
  2. age: 30,
  3. set name(name) {
  4. console.log(this);
  5. console.log('-------');
  6. }
  7. };
  8. const res = Reflect.set(obj, 'age', 31);
  9. console.log(res); // true
  10. console.log(obj); // {age: 31, set name:function}
  11. /*
  12. {age: 31, set name:function}, true
  13. */
  14. const res2 = Reflect.set(obj, 'name', 'xxxx');
  15. console.log(res2); // true
  16. /*
  17. 先执行 set 中的name方法,打印 console.log(this);this就指向了第四个参数 {test: 'test'}
  18. 然后会打印 '-----';
  19. */
  20. const res3 = Reflect.set(obj, 'name', 'xxxx', {test: 'test'}); // this: --> { test: 'test' }
  21. console.log(res3); // true
  22. console.log(obj); // { name: [Setter], age: 31 }

Reflect.apply()

**Reflect.apply(target, thisArg, args)**函数的作用是通过指定的参数列表执行target函数,等同于执行Function.prototype.apply.call(target, thisArg,args)
target: 目标函数.
thisArg: 执行target函数时的this对象。
args: 函数参数列表。

  1. // 查找数组里面最小的元素值
  2. const arrs = [1, 2, 3, 4];
  3. // ES6 的语法如下
  4. const min = Reflect.apply(Math.min, null, arrs);
  5. console.log(min); // 1
  6. // ES5的语法如下:
  7. const min2 = Math.min.apply(null, arrs);
  8. console.log(min2); // 1
  9. // 或者使用 Finction.prototype 代码如下演示
  10. const min3 = Function.prototype.apply.call(Math.min, null, arrs);
  11. console.log(min3); // 1
  12. // 截取字符串的方法
  13. const strs = 'kongzhi';
  14. // 使用ES6的语法 代码演示如下:
  15. const str1 = Reflect.apply(String.prototype.slice, strs, [0, 3]);
  16. console.log(str1); // kon
  17. // 使用 ES5的语法
  18. const str2 = strs.slice(0, 3);
  19. console.log(str2); // kon
  20. // 或者使用 String.prototype 代码如下演示
  21. const str3 = String.prototype.slice.apply(strs, [0, 3]);
  22. console.log(str3); // kon

Reflect.construct()

**Reflect.construct(target, args [, newTarget])**函数的作用是执行构造函数,等同于执行new target(...args)
target: 被运行的目标构造函数。
args: 调用构造函数传递的参数列表。
newTarget(可选): 也是构造函数,有则表示将newTarget作为新的构造函数,此时使用 Reflect.construct后生成的实列由两部分组成,实列的属性部分由target构造函数生成。实列的方法由newTarget构造函数生成。如果没有该参数,默认生成的实列对象就和target构造函数是一样的。

  1. function XXXX(name) {
  2. this.name = name;
  3. }
  4. XXXX.prototype.getName = function() {
  5. return this.name;
  6. }
  7. function YYYY(age) {
  8. this.age = age;
  9. }
  10. YYYY.prototype.getAge = function() {
  11. return this.age || 31;
  12. }
  13. // 使用 XXXX函数作为构造函数, 那么构造函数就指向了 XXXX函数
  14. const xxxx = Reflect.construct(XXXX, ['xx']);
  15. console.log(xxxx); // XXXX {name: xx}
  16. console.log(xxxx.getName()); // xx
  17. // 使用 YYYY 函数作为构造函数,那么构造函数就指向了 YYYY函数,但是生成的实例yyyy获取不到YYYY的属性,只能获取到方法,属性还是原来的XXXX属性
  18. const yyyy = Reflect.construct(XXXX, ['30'], YYYY);
  19. console.log(yyyy); // YYYY {name: 30}
  20. console.log(yyyy.name); // 30
  21. console.log(yyyy.age); // undefined
  22. console.log(yyyy instanceof YYYY); // true
  23. console.log(yyyy instanceof XXXX); // false
  24. console.log(yyyy.getAge()); // 31

Reflect.defineProperty()

**Reflect.defineProperty(target, propKey,attributes)**等同于Object.defineProperty方法,唯一的区别是 Reflect.defineProperty返回值是一个Boolean值。
target:定义属性的目标对象
propKey:新增的属性名
attributes:属性描述符对象集

  1. const obj = {};
  2. // 使用 Object.defineProperty
  3. try {
  4. Object.defineProperty(obj, 'a', {
  5. value: 22
  6. })
  7. } catch(e) {
  8. console.log('define property failed');
  9. }
  10. // 使用 Reflect.defineProperty
  11. const res = Reflect.defineProperty(obj, 'b', {
  12. configurable: true,
  13. enumerable: true
  14. });
  15. console.log(res); // true

Reflect.deleteProperty()

**Reflect.deleteProperty(target, propKey)**删除对象的属性,等同于执行delete obj[propKey],返回值是一个Boolean的值
target: 待删除属性的对象。
propKey: 待删除的属性。

  1. const obj = {
  2. name: 'kongzhi',
  3. age: 30
  4. };
  5. let test1 = Reflect.deleteProperty(obj, 'name');
  6. console.log(test1); // true
  7. console.log(obj); // {age: 30}
  8. // 如果删除对象上不存在的属性的话,也是返回true的
  9. let test2 = Reflect.deleteProperty(obj, 'xx');
  10. console.log(test2); // true
  11. console.log(obj); // {age: 30}

Reflect.has()

**Reflect.has(target, propKey)**判断一个对象上是否含有特定的属性,等相当于es5中的in操作符。
target: 目标对象。
propKey: 判断的属性。

  1. // 一般的对象
  2. const obj = {
  3. name: 'kongzhi',
  4. age: 30
  5. };
  6. console.log(Reflect.has(obj, 'name')); // true
  7. console.log(Reflect.has(obj, 'username')); // 该对象上没有 username属性 返回false
  8. console.log(Reflect.has(obj, 'age')); // true
  9. // 函数的实列
  10. function Obj(name) {
  11. this.name = name;
  12. }
  13. Obj.prototype.getName = function() {
  14. return this.name;
  15. }
  16. const test = new Obj();
  17. // 使用in操作符测试
  18. console.log('name' in test); // true
  19. console.log('getName' in test); // true
  20. // 使用Reflect.has 测试
  21. console.log(Reflect.has(test, 'name')); // true
  22. console.log(Reflect.has(test, 'getName')); // true

Reflect.ownKeys()

**Reflect.ownKeys(target)**获取目标对象的所有属性,包括Symbol属性,等同于Object.getOwnPropertyNamesObject.getOwnPropertySymbols之和。

Reflect.preventExtensions()

**Reflect.preventExtensions(target)**让一个对象变得不可扩展,等同于执行Object.preventExtensions()

  1. const obj = {};
  2. // 判断该对象是否可以扩展,使用 Reflect.isExtensible 该方法
  3. console.log(Reflect.isExtensible(obj)); // true
  4. // 使用 Reflect.preventExtensions 来阻止该对象扩展
  5. Reflect.preventExtensions(obj);
  6. console.log(Reflect.isExtensible(obj)); // false

Reflect.isExtensible()

**Reflect.isExtensible(target)**函数的作用是判断对象是否可扩展,等同于执行Object.isExtensible()函数。该函数会返回一个Boolean值

Reflect.getOwnPropertyDescriptor()

**Reflect.getOwnPropertyDescriptor(target,propKey)**得到指定属性的描述对象,等同于执行Object.getOwnPropertyDescriptor()

  1. const obj = {};
  2. Reflect.defineProperty(obj, 'name', {
  3. configurable: true,
  4. enumerable: true,
  5. writable: true,
  6. value: '30'
  7. });
  8. const test1 = Reflect.getOwnPropertyDescriptor(obj, 'name');
  9. console.log(test1);
  10. /*
  11. 打印值如下:
  12. {
  13. configurable: true
  14. enumerable: true
  15. value: "30"
  16. writable: true
  17. }
  18. */
  19. const test2 = Reflect.getOwnPropertyDescriptor(obj, 'age');
  20. console.log(test2); // undefined
  21. // 如果第一个参数不是对象
  22. const test3 = Object.getOwnPropertyDescriptor('kkkk', 'name');
  23. console.log(test3); // undefined
  24. // 使用 try catch 包围,会执行 catch方法内部代码
  25. try {
  26. const test4 = Reflect.getOwnPropertyDescriptor('kkkk', 'name');
  27. console.log(test4);
  28. } catch (e) {
  29. console.log('error');
  30. }

Reflect.getPrototypeOf()

Reflect.getPrototypeOf(target)读取对象的proto属性,等同于执行Object.getPrototypeOf(obj)

Reflect.setPrototypeOf()

**Reflect.setPrototypeOf(target, newProto)**设置对象的原型prototype,等同于执行Object.setPrototypeOf(target, newProto)。返回值是Boolean值,设置成功,返回true,设置失败返回false。

  1. const obj = {};
  2. const test1 = Reflect.setPrototypeOf(obj, Object.prototype);
  3. console.log(test1); // true
  4. let test2 = Reflect.setPrototypeOf(Object.freeze({}), null);
  5. console.log(test2); // false