Reflect
Reflect对象的设计目的有这样几个
- 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和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方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
方法跟Proxy的方法一一对应
//Reflect.apply(target,thisArg,args)
// Reflect.construct(target, args)
// Reflect.get(target, name, receiver)
// Reflect.set(target, name, value, receiver)
// Reflect.defineProperty(target, name, desc)
// Reflect.deleteProperty(target, name)
// Reflect.has(target, name)
// Reflect.ownKeys(target)
// Reflect.isExtensible(target)
// Reflect.preventExtensions(target)
// Reflect.getOwnPropertyDescriptor(target, name)
// Reflect.getPrototypeOf(target)
// Reflect.setPrototypeOf(target, prototype)
console.log('assign' in Object); //true
console.log(Reflect.has(Object, 'assign')) //true
var obj = {
get foo() { console.log(this); return this.bar(); },
bar: function () { console.log('bar') },
construct: function(target, args) {
console.log('construct')
return { value: args[1] };
}
};
//定义一个cc类
var cc = {
foo() { console.log('cc.foo')},
bar() { console.log('cc.bar') }
};
// (1)Reflect.get(target, name, receiver)
console.log(Reflect.get(obj, 'bar'))
// 下面语句会让 this.bar()
// // 变成调用 cc.bar()
Reflect.get(obj, "foo", cc); //传递cc进去,就会改变this为cc
// 查找并返回target对象的name属性,如果没有该属性,则返回undefined。
// 如果name属性部署了读取函数,则读取函数的this绑定receiver。
// var obj = {
// get foo() { return this.bar(); },
// bar: function () { ... }
// };
(2)Reflect.set(target, name, value, receiver)
设置target对象的name属性等于value。如果name属性设置了赋值函数,则赋值函数的this绑定receiver。
如果target对象中指定了getter,receiver则为getter调用时的this值。
console.log(Reflect.set(obj, 'ES6', 'Reflect'), obj);
(3)Reflect.has(obj, name)
console.log(Reflect.has(obj, 'ES6')) //true
等同于name in obj。
(4)Reflect.deleteProperty(obj, name)
等同于delete obj[name]。
console.log(Reflect.deleteProperty(obj, 'ES6')) //true
(5)Reflect.construct(target, args)
等同于new target(…args) ,这提供了一种不使用new,来调用构造函数的方法。
function Person(a) {console.log(a);}
// Reflect.construct(target,args) //在proxy内部使用,用来作为返回结果
(6)Reflect.getPrototypeOf(obj)
读取对象的__proto__属性,对应Object.getPrototypeOf(obj) 。
(7)Reflect.setPrototypeOf(obj, newProto)
设置对象的__proto__属性,对应Object.setPrototypeOf(obj, newProto) 。
(8)Reflect.apply(fun, thisArg, args)
等同于Function.prototype.apply.call(fun, thisArg, args) 。一般来说,如果要绑定一个函数的this对象,可以这样写fn.apply(obj, args) ,但是如果函数定义了自己的apply方法,就只能写成Function.prototype.apply.call(fn, obj, args) ,采用Reflect对象可以简化这种操作。
console.log( Function.prototype.apply.call(Math.floor, undefined, [1.75])) //1
console.log(Reflect.apply(Math.floor, undefined, [1.75])) //1
另外,需要注意的是,Reflect.set() 、Reflect.defineProperty() 、Reflect.freeze() 、Reflect.seal()和Reflect.preventExtensions()返回一个布尔值,表示操作是否成功。它们对应的Object方法,失败时都会抛出错误。
失败时抛出错误
Object.defineProperty(obj, name, desc);
失败时返回false
Reflect.defineProperty(obj, name, desc);
上面代码中,Reflect.defineProperty方法的作用与Object.defineProperty是一样的,都是为对象定义一个属性。但是,Reflect.defineProperty方法失败时,不会抛出错误,只会返回false。
观察者模式
const queuedObservers = new Set();
//创建一个Set集合
const observe = fn => queuedObservers.add(fn);
//添加观察者回调到集合中
const observable = obj => new Proxy(obj, { set });
//Proxy监听
function set(target, key, value, receiver) {
//调用Reflect的set方法来设置值
const result = Reflect.set(target, key, value, receiver);
//循环遍历监听队列
queuedObservers.forEach(observer => observer());
return result;
}
const person = observable({
name: '张三',
age: 20
});
function print() {
console.log(`${person.name}, ${person.age}`)
}
observe(print);
person.name = '李四';
// 输出
// 李四, 20