Reflect概述及应用

Reflect概述

Reflect是ES6提供的操作对象的Api,其主要目的有

  • 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。
  • 修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
  • 让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
  • Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。

Reflect静态方法

  • Reflect.get(target,name,receiver):查找并返回target对象的name属性,如果没有该属性返回undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
}

var myReceiverObject = {
foo: 4,
bar: 4,
};
// Reflect.get的第一个参数不是对象会报错
Reflect.get(myObject, 'foo') // 1
Reflect.get(myObject, 'bar') // 2
Reflect.get(myObject, 'baz') // 3
// 如果有reciver参数则getter的this绑定receiver
Reflect.get(myObject, 'baz', myReceiverObject) // 8
  • Reflect.set(target,name,value,receiver):设置对象的name属性值为value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var myObject = {
foo: 4,
set bar(value) {
return this.foo = value;
},
};

var myReceiverObject = {
foo: 0,
};

Reflect.set(myObject, 'bar', 1, myReceiverObject);
myObject.foo // 4
myReceiverObject.foo // 1
  • Reflect.has(obj,name):判断obj对象是否包含name属性
1
2
3
4
5
6
7
8
var myObject = {
foo: 1,
};

// 旧写法
'foo' in myObject // true
// 新写法
Reflect.has(myObject, 'foo') // true
  • Reflect.deleteProperty(obj, name):等同于delete obj[name]方法,删除对象的name属性值
1
2
3
4
5
6
const myObj = { foo: 'bar' };

// 旧写法
delete myObj.foo;
// 新写法
Reflect.deleteProperty(myObj, 'foo');
  • Reflect.construct(target,args):等同于new target(…args)提供了一种不使用new调用构造函数的方法。
1
2
3
4
5
6
7
8
function Greeting(name) {
this.name = name;
}

// new 的写法
const instance = new Greeting('张三');
// Reflect.construct 的写法
const instance = Reflect.construct(Greeting, ['张三']);
  • Reflect.apply(func,thisArg,args):等同于Function.prototype.apply.call(func,thisArg,args)用于绑定this对象后执行给定函数。
1
2
3
4
5
6
7
8
9
10
11
const ages = [11, 33, 12, 54, 18, 96];

// 旧写法
const youngest = Math.min.apply(Math, ages);
const oldest = Math.max.apply(Math, ages);
const type = Object.prototype.toString.call(youngest);

// 新写法
const youngest = Reflect.apply(Math.min, Math, ages);
const oldest = Reflect.apply(Math.max, Math, ages);
const type = Reflect.apply(Object.prototype.toString, youngest, []);
  • Reflect.ownKeys(target):返回对象的所有属性,等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var myObject = {
foo: 1,
bar: 2,
[Symbol.for('baz')]: 3,
[Symbol.for('bing')]: 4,
};

// 旧写法
Object.getOwnPropertyNames(myObject)
// ['foo', 'bar']

Object.getOwnPropertySymbols(myObject)
//[Symbol(baz), Symbol(bing)]

// 新写法
Reflect.ownKeys(myObject)
// ['foo', 'bar', Symbol(baz), Symbol(bing)]

实例:使用Proxy和Reflect实现观察者模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 观察目标
const person = observable({
name: '张三',
age: 20
});
// 观察者
function print() {
console.log(`${person.name}, ${person.age}`)
}

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

实现:

1
2
3
4
5
6
7
8
9
10
const queuedObservers = new Set();

const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set});

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