# Reflect
- Reflect 同 Proxy 一样,都是ES6为了操作对象而提供的新API,设计目的:
- 将 Object 一些明显属于语言内部的方法(如 Object.defineProperty),放到 Reflect对象上,
现阶段,某些方法同时放在 Reflect 和 Proxy 对象上部署,未来的新方法只部署在 Reflect 上。Reflect对象上
可以拿到语言内部的方法。 - 修改某些 Object 方法的返回结果。比如 Object.defineProperty(obj, name, desc) 在无法定义属性时会抛出错误,
而 Reflect.defineProperty(obj, name, desc) 则会返回 false。
// Object.defineProperty 无法定义属性时会抛出错误 所以防止报错写法如下
try {
// 重复定义会报错
Object.defineProperty(obj, 'name', { value: 'hello' })
} catch (error) {
console.log(error);
}
// Reflect.defineProperty 返回 true false
if (Reflect.defineProperty(obj, 'age', { value: 12 })) {
// ...
} else {
// ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
让 Object 操作变成函数行为。某些 Object 操作是命令式,比如
name in obj
和delete obj[name]
,
Reflect.has(obj, name)
和Reflect.deleteProerty(obj, name)
变成函数行为。Reflect 对象的方法和 Proxy 一一对应,只要是 Proxy 对象的方法,都能在 Reflect 对象上找到对应的方法,这让
Proxy 对象可以方便的调用对应的 Reflect 的方法,完成默认行为,作为修改行为的基础。不管 Proxy 怎么修改默认行为,
总可以在 Reflect 上获取默认行为。
const person = {
name: 'Hello',
age: 12
};
const p = new Proxy(person, {
get: function(target, name) {
console.log('get handler');
return Reflect.get(target, name);
},
set(target, name, value) {
console.log('set handler');
return Reflect.set(target, name, value);
}
})
p.name; // get handler
p.age = 14; // set handler
console.log(p); // { name: 'Hello', age: 14}
// 保证原生行为能够正常执行,通知增加日志输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- 有了 Reflect 后 很多操作会更易读
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1
Reflect.apply(Math.floor, undefined, [1.75]) // 1
1
2
3
2
3
# Reflect.get(target, name, receiver)
- 返回
target
对象中name
属性, 没有 name 属性,则返回 undefined
const person = {
name: 'Hello',
age: 12
};
console.log(Reflect.get(person, 'name')); // 'Hello'
console.log(Reflect.get(person, 'sex')); // undefined
1
2
3
4
5
6
7
2
3
4
5
6
7
- 如果 name 部署了读取函数(getter),则读取函数的
this
绑定receiver
const person = {
name: 'Hello',
age: 12,
get fn() {
return `${this.name}-${this.age}`;
},
nFn() {
return `${this.name}-${this.age}`;
}
};
const receiverObj = {
name: 'Ben',
age: 18
}
const ret = Reflect.get(person, 'fn', receiverObj);
console.log(ret); // Ben-18
const ret2 = Reflect.get(person, 'nFn', receiverObj);
console.log(ret2); // Function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 如果第一个参数不是对象,则报错
Reflect.get(false, 'name') // Error
Reflect.get(1, 'name') // Error
1
2
2
# Reflect.set(target, name, value, receiver)
设置 target 对象 name 属性的值为 value
如果 name 属性设置的赋值函数,则赋值函数的 this 绑定 receiver
const setObj = {
boo: 1,
foo: 2,
set fn(value) {
return this.foo = value;
}
}
Reflect.set(setObj, 'boo', 3);
console.log(setObj.boo); // 3
const setReceiver = {
foo: 5
}
Reflect.set(setObj, 'fn', 4, setReceiver)
console.log(setObj.foo); // 2
console.log(setReceiver.foo); // 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- 如果 Proxy 和 Reflect 联合使用,Proxy 完成拦截赋值操作,Reflect 完成赋值的默认行为。
如果传入 receiver ,那么 Reflect.set() 会触发 Proxy.defineProperty 拦截操作
const ob = {
a: 1
}
const handler = {
set(target, name, value, receiver) {
console.log('set');
Reflect.set(target, name, value, receiver);
},
defineProperty(target, name, attr) {
console.log('defineProperty');
Reflect.defineProperty(target, name, attr);
}
}
const o = new Proxy(ob, handler);
o.a = 2
// set
// defineProperty
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Reflect.has(target, key)
- 对应
key in obj
的in
操作符
# Reflect.deleteProperty(target, key)
- 对应
delete obj[key]
- 返回布尔值
# Reflect.construct(target, args)
- 等同于
new target(...args)
function Hello(name, str) {
console.log(name, str); // 2 'You'
this.name = name;
}
const ins = Reflect.construct(Hello, [2, 'You', 1, 3, 4])
console.log(ins.name); // 2
1
2
3
4
5
6
7
2
3
4
5
6
7