从零开始学_JavaScript_系列(47)——Reflect

Reflect

1、是什么?

  1. window的原生对象,但不能通过new来生成实例;
  2. 对对象的属性的操作,都可以通过这个来完成(读、写、定义属性等);
  3. 返回值更加合理(失败返回false而不是抛错);
  4. 函数式调用(而非属性式)
  5. 在使用Proxy时,使用本方法效果比直接通过对象属性调用效果更好

2、如何使用(几种常见方法示例)

2.1、读

Reflect.get(target, propertyKey[, receiver])

拦截对target对象的propertyKey属性的读取,返回这个属性的值。

  1. 参数一是被访问的对象;
  2. 参数二是属性名;
  3. 参数三当遇见getter时,将getter的this指向他

参数一和参数二好理解,如代码:

let target = {
    _test: 1,
    get test() {
        return this._test;
    }
};

Reflect.get(target, "_test");   //1
Reflect.get(target, "test");    //1

参数三比较特殊,当遇见getter时,getter的this将指向他。下面代码可以很好的体现这一点:

let receiver = {_test: 2}
let target = {
    _test: 1,
    get test() {
        console.log(this === target, this === receiver);
        return this._test;
    }
};

Reflect.get(target, "test", receiver);
// false true
// 2

target.test;
// true false
// 1

通过Reflect.get调用时(且有第三个参数),this指向参数三;
当通过target.test调用时,this指向对象本身;

2.2、写

Reflect.set(target, propertyKey, value[, receiver])

如果理解Reflect.get了,那么理解Reflect.set自然也很简单了。

  1. 参数一是目标对象;
  2. 参数二是属性名;
  3. 参数三是要设置的值;
  4. 参数四是遇见setter时,this指向的目标;
  5. 返回值是是否设置成功,成功则为true,报错为false;

如代码:

let receiver = {_test: 2};
let target = {
    _test: 1,
    get test() {
        return this._test;
    },
    set test(val) {
        this._test = val;
    }
};

Reflect.set(target, "test", "a");   //true
target.test;    //"a"

//修改setter的this指向目标
Reflect.set(target, "test", "b", receiver);   //true
target.test;    //"a"
receiver._test; //"b"

//修改被禁止修改的属性
Object.defineProperty(target, "test", {
    value: 1
});
Reflect.set(target, "test", "a");   //false
target.test;    //1

3、观察者模式

观察者模式是结合了Proxy代理以及Reflect实现的,重点是Proxy。

我这里对阮一峰给的示例代码略有修改,并添加注释,以示使用方法:

//存储观察者函数,用数组也可以
const queuedObservers = new Set();
// const queuedObservers = [];

//定义observe函数,执行本函数会将观察者函数添加到queuedObservers中,返回的是观察者函数的列表
const observe = fn => queuedObservers.add(fn);
// const observe = fn => queuedObservers.push(fn);

//定义observable函数,将该对象添加代理后返回proxy实例
const observable = obj => new Proxy(obj, {set});

//handler,执行时会调用观察者里函数里的每个观察者
function set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    queuedObservers.forEach(observer => observer(key, value));
    return result;
}

//对对象进行代理绑定
const person = observable({
    name: '张三',
    age: 20
});

//定义2个函数
function printKey(key, value) {
    console.log("key: " + key)
}
function printValue(key, value) {
    console.log("value: " + value)
}

//将函数设置为观察者函数
observe(printKey);
observe(printValue);

//调用person(proxy实例)的属性name
person.name = '李四';
//输出
//key: name
//value: 李四

//创建另外一个被观察的对象(空)
const foo = observable({});
//给他添加一个属性(触发set),因此会触发所有添加到观察者里的函数
foo.fruit = "梨";
//输出
//key: fruit
//value: 梨

简单来说:

  1. 可以创建一个函数用于进行proxy绑定(observable);
  2. 并且创建一个观察者列表,用于添加你的观察者函数(列表queuedObservers,添加函数observe);
  3. 因为是proxy,所以你还需要一个handler,并且假定你handler里的set会执行所有观察者函数;
  4. 然后所有被绑定过的函数,在使用它的返回值时(即proxy实例),你设置对象属性就会触发handler的set,而set就会执行所有观察者函数;
  5. 于是有了上面示例代码发生的情况;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值