zoukankan      html  css  js  c++  java
  • 浅谈ES6中的Proxy

    Proxy是一个很有趣的对象,它能够修改某些操作的默认行为,等同于在语言层面做出修改,属于一种‘元编程’,即对编程语言进行编程。

    Proxy其实很好理解,就是在目标对象之前架设一层拦截,外界的访问都得通过这层拦截,所以我们可以实现对外界访问的过滤和改写。

    Proxy的使用其实很简单,举几个栗子你就清楚了:

    我们重新定义属性的读取(get)和设置(set)行为,当我读取Person对象的age属性时,当age属性值大于100时,就让它等于99:

    var person = {
        name:'fancy',
        age:123
    }//定义一个对象
    var  proxy = new Proxy(person,//第一个参数传要代理的对象
    {//第二个参数传要重定义的属性
        get:(target,key)=>{
            if (key == 'age'&& target[key] > 100) {
                return 99
            }else{
                return target[key]
            }
        }
    });
    proxy.name //fancy
    proxy.age //99
    person.age //123    

    我们创建了一个Proxy对象去代理person对象,并将属性的get方法重定义,当属性值等于‘age’并且值大于100时,返回99,否则直接返回属性值。get接收两个参数,第一个是原对象,第二个是属性名。

    数据打印出来后,发现proxy的age值变成了99,而person的age值仍然是123,proxy实际上是重载(overload)了点运算符,用自己的定义覆盖了语言的原始定义。


    我们再用set方法用来拦截某个属性的赋值操作。

    假定Person对象有一个age属性,该属性应该是一个不大于200的整数,那么可以使用Proxy保证age的属性值符合要求。

    let validator = {
      set: function(obj, prop, value) {
        if (prop === 'age') {
          if (!Number.isInteger(value)) {
            throw new TypeError('The age is not an integer');
          }
          if (value > 200) {
            throw new RangeError('The age seems invalid');
          }
        }
        // 对于age以外的属性,直接保存
        obj[prop] = value;
      }
    };
    let person = new Proxy({}, validator);
    
    person.age = 100;
    
    person.age // 100
    person.age = 'young' // 抛出异常:The age is not an integer
    person.age = 300 // 抛出异常:The age seems invalid

    set方法也常常用来做数据绑定,当对象发生改变时,自动更新视图;还可以用来禁止读写内部属性等等。

    Proxy对象可以支持的拦截操作总结了下,大概以下13种:

    (1)get(target, propKey, receiver)

    拦截对象属性的读取,比如proxy.fooproxy['foo']

    最后一个参数receiver是一个对象,可选,参见下面Reflect.get的部分。

    (2)set(target, propKey, value, receiver)

    拦截对象属性的设置,比如proxy.foo = vproxy['foo'] = v,返回一个布尔值。

    (3)has(target, propKey)

    拦截propKey in proxy的操作,以及对象的hasOwnProperty方法,返回一个布尔值。

    (4)deleteProperty(target, propKey)

    拦截delete proxy[propKey]的操作,返回一个布尔值。

    (5)ownKeys(target)

    拦截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy),返回一个数组。该方法返回对象所有自身的属性,而Object.keys()仅返回对象可遍历的属性。

    (6)getOwnPropertyDescriptor(target, propKey)

    拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。

    (7)defineProperty(target, propKey, propDesc)

    拦截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。

    (8)preventExtensions(target)

    拦截Object.preventExtensions(proxy),返回一个布尔值。

    (9)getPrototypeOf(target)

    拦截Object.getPrototypeOf(proxy),返回一个对象。

    (10)isExtensible(target)

    拦截Object.isExtensible(proxy),返回一个布尔值。

    (11)setPrototypeOf(target, proto)

    拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。

    如果目标对象是函数,那么还有两种额外操作可以拦截。

    (12)apply(target, object, args)

    拦截Proxy实例作为函数调用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)

    (13)construct(target, args)

    拦截Proxy实例作为构造函数调用的操作,比如new proxy(...args)


    网上有很多实例可以参考,这里就不一一列举了,有兴趣自己写框架的朋友,可以深究一下Proxy的实现原理。

  • 相关阅读:
    正则表达式解析
    Selenium自动化测试系列文章汇总
    Python自动化测试-正则表达式解析
    滴滴滴,ITester软件测试小栈所有资源放送!
    Selenium自动化测试-文件上传
    Selenium自动化测试-浏览器基本操作
    2020牛客暑期多校第四场-H Harder Gcd Problem(贪心构造)
    2020牛客暑期多校第三场F-Fraction Construction Problem-分数构造题(拓展欧几里得)
    洛谷P1919--A*B Problem升级版(NTT优化高精度乘法)
    洛谷P4721-分治FFT(NTT分治)
  • 原文地址:https://www.cnblogs.com/chinajins/p/5941443.html
Copyright © 2011-2022 走看看