美文网首页
Proxy与Reflect

Proxy与Reflect

作者: nomooo | 来源:发表于2018-12-27 23:33 被阅读0次

    Proxy

    Proxy可以理解成,在目标对象之前架一层‘拦截’,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来‘代理’某些操作,可以译为“代理器”

        var proxy = new Proxy(target,handler);
    

    Proxy对象的所有用法,都是上面这种形式,不同的只是handler参数的写法,其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为

    • 举一个拦截器读取属性行为的🌰

        var proxy = new Proxy({}, {
            //get方法的两个参数:目标对象、索要访问的属性
            //可以看到,拦截函数总是返回100,所以任何属性都得到35
            get: function(target, property) {
                return 100;
            }
        })
      
        console.log(proxy.name); // 100
        console.log(proxy.time); // 100
        console.log(proxy.age); // 100
      

    注意:要使得Proxy起作用,必须针对Proxy实例进行操作,而不是针对目标对象进行操作
    如果handler没有设置任何拦截,那就等同于直接通向原对象

    一个技巧是将Proxy对象,设置到object.proxy属性,从而可以在object对象上调用
    var object = { proxy: new Proxy(target, handler) }

    • Proxy实例也可以作为其他对象的原型对象

        var proxy = new Proxy({}, {
            get: function(target, property) {
                return 100;
            }
        })
      
        let obj = Object.create(proxy);
        console.log(obj.title);//100
      

    上面代码中,proxy对象是obj对象的原型,obj对象本身并没有time属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截

    同一个拦截器,可以设置多个拦截操作,如果对于可以设置,但是没有设置拦截的操作,则直接落在目标对象上,按照原先的方法产生结果

    Proxy支持的拦截操作一共是13中:

    • get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。
    • set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
    • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
    • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
    • ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
    • getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
    • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
    • preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
    • getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
    • isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
    • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
    • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
    • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。

    Reflect

    Reflect对象与Proxy对象一样,也是ES6为了操作对象而提供的新的API。Reflect对象的设计目的有这样几个。

    • 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新的方法将部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法

    • 修改某些Object方法的返回解构,让其变得更合理,比如Object.defineProperty(obj,name,desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj,name,desc)则会返回false

        //老写法
      
        try {
            Object.defineProperty(target, property, attributes)
            //success
        } catch (e) {
            //failure
        }
      
        //新写法
      
        if(Reflect.defineProperty(target, property, attributes)){
            //success
        }else{
            //failure
        }
      
    • 让Object操作都变成函数行为,某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj,name)和Reflect.deleteProperty(obj,name)让他们变成了函数行为

        //老写法
        'name' in obj
      
        //新写法
        Reflect.has(obj,'name')
      
    • Reflect对象的方法与Proxy对象的方法一一对应。只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法,这就让Proxy对象可以方便的调用对应的Reflect方法,完成默认行为,作为修改行为的基础,也就是说,不管Proxy怎么修改默认行为,总可以在Reflect上获取默认行为

        Proxy(target, {
            //Proxy方法拦截target对象的属性赋值行为。
            //它采用Reflect.set方法将值赋值给对象的属性,确保完成原有的行为,然后再部署额外的功能。
            set: function(target, name, value, receiver) {
            var success = Reflect.set(target,name, value, receiver);
            if (success) {
                console.log('property ' + name + ' on ' + target + ' set to ' + value);
            }
            return success;
            }
        });
      

    有了Reflect对象之后,很多操作会更易读

        // 老写法
        Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1
    
        // 新写法
        Reflect.apply(Math.floor, undefined, [1.75]) // 1
    

    Reflect对象一共有13个静态方法,大部分与Object对象的同名做法的作用相同,而且它与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)

    相关文章

      网友评论

          本文标题:Proxy与Reflect

          本文链接:https://www.haomeiwen.com/subject/eacllqtx.html