代理和反射

reflect

它是JS的内置对象,开发者可以通过调用这些方法,访问一些JS底层原理。

reflect做什么

使用Reflect可以实现诸如 属性的赋值与取值、调用普通函数、调用构造函数、判断属性是否存在与对象中 等等功能

这些功能不是已经存在了吗?为什么还需要用Reflect实现一次?

有一个重要的理念,在ES5就被提出:减少魔法、让代码更加纯粹

这种理念很大程度上是受到函数式编程的影响

ES6进一步贯彻了这种理念,它认为,对属性内存的控制、原型链的修改、函数的调用等等,这些都属于底层实现,属于一种魔法,因此,需要将它们提取出来,形成一个正常的API,并高度聚合到某个对象中,于是,就造就了Reflect对象

因此,你可以看到Reflect对象中有很多的API都可以使用过去的某种语法或其他API实现。

有哪些API

  • Reflect.set(target, propertyKey, value): 设置对象target的属性propertyKey的值为value,等同于给对象的属性赋值
  • Reflect.get(target, propertyKey): 读取对象target的属性propertyKey,等同于读取对象的属性值
  • Reflect.apply(target, thisArgument, argumentsList):调用一个指定的函数,并绑定this和参数列表。等同于函数调用
  • Reflect.deleteProperty(target, propertyKey):删除一个对象的属性
  • Reflect.defineProperty(target, propertyKey, attributes):类似于Object.defineProperty,不同的是如果配置出现问题,返回false而不是报错
  • Reflect.construct(target, argumentsList):用构造函数的方式创建一个对象
  • Reflect.has(target, propertyKey): 判断一个对象是否拥有一个属性
  • 其他API:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

案例

const obj = {
    a: 1,
}
Reflect.set(obj,'b',1221);
console.log(Reflect.get(obj,'b')); // 1221

Proxy

代理:提供了修改底层实现的方式


//代理一个目标对象
//target:目标对象
//handler:是一个普通对象,其中可以重写底层实现
//返回一个代理对象
new Proxy(target, handler)

案例

const obj = {
    a: 1,
    b: 2
}

// 通过操作obj的代理,来间接操作obj
const objProxy = new Proxy(obj, {
    set(target, propertyKey, value) {
        Reflect.set(target, propertyKey, value);
    },
    get(target, propertyKey) {
        if (Reflect.has(target, propertyKey)) {
           return Reflect.get(target, propertyKey);
        } else {
            return -1;
        }
    },
    has(target, propertyKey) {
        return false;
    }
})

objProxy.a = 123;
console.log('a' in objProxy); // false
console.log(objProxy.a); // 123

观察者模式

有一个对象,是观察者,它用于观察另外一个对象的属性值变化,当属性值变化后会收到一个通知,可能会做一些事。

 function observer(target) {
            const ob = {};
            const div = document.getElementById('container');
            const props = Object.keys(target);
            for (const prop of props) {
                Object.defineProperty(ob, prop, {
                    get() {
                        return target[prop];
                    },
                    set(val) {
                        target[prop] = val;
                        render();
                    },
                    enumerable: true
                })
            }
            render();

            function render() {
                let html = '';
                for (const prop of Object.keys(ob)) {
                    html += `<p><span>${prop}: ${ob[prop]}</span></p>`
                }
                div.innerHTML = html;
            }
            return ob;
        }
        const target = {
            a: 1212,
            age: 24
        }
       const obj = observer(target);

使用Object.defineProperty会增加一个新的对象。直接改变target无法监听。

  • 改进版
//创建一个观察者
     function observer(target) {
         const div = document.getElementById("container");
         const proxy = new Proxy(target, {
             set(target, prop, value) {
                 Reflect.set(target, prop, value);
                 render();
             },
             get(target, prop){
                 return Reflect.get(target, prop);
             }
         })
         render();

         function render() {
             let html = "";
             for (const prop of Object.keys(target)) {
                 html += `
                     <p><span>${prop}:</span><span>${target[prop]}</span></p>
                 `;
             }
             div.innerHTML = html;
         }

         return proxy;
     }
     const target = {
         a: 1,
         b: 2
     }
     const obj = observer(target)

proxy不会增加一个新的对象,会监听所有属性改变。

偷懒的构造函数

class User {

}

function ConstructorProxy(className, ...propName) {
    return new Proxy(className, {
        construct(target, argumentsList) {
            const obj = Reflect.construct(target, argumentsList);
            propName.forEach((name, i)=>{
                obj[name] = argumentsList[i+1];
            })
            return obj;
        }
    })
}

const userConstructor = ConstructorProxy(User, 'firstName', 'lastName', 'age');

const obj = new userConstructor(User, 'chou', 'jay', 18);
console.log(obj);
// User { firstName: 'chou', lastName: 'jay', age: 18 }

可验证函数参数类型

function sum(a, b) {
            return a + b;
        }

        function validatorFunction(func, ...types) {
            const proxy = new Proxy(func, {
                apply(target, thisArgument, argumentsList) {
                    types.forEach((t, i) => {
                        const arg = argumentsList[i]
                        if (typeof arg !== t) {
                            throw new TypeError(`第${i+1}个参数${argumentsList[i]}不满足类型${t}`);
                        }
                    })
                    return Reflect.apply(target, thisArgument, argumentsList);
                }
            })
            return proxy;
        }

        const sumProxy = validatorFunction(sum, "number", "number")
        console.log(sumProxy(1, 2))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值