最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Proxy实际用法

    正文概述 掘金(你程弟)   2021-03-26   497

    1. Default/ “Zero Values”

    给对象(包括数组)提供zero values. zero values分别是Boolean(false), Number(0), String(''), Object({}), Array([])等等.

    const withZeroValue = (target, zeroValue) => new Proxy(target, {
      get: (obj, prop) => (prop in obj) ? obj[prop] : zeroValue
    })
    
    let pos = {
      x: 4,
      y: 19
    }
    
    console.log(pos.x, pos.y, pos.z) // 4, 19, undefined
    
    pos = withZeroValue(pos, 0)
    
    console.log(pos.x, pos.y, pos.z) // 4, 19, 0
    

    2. Negative Array Indices

    获取数组的最后一个元素在JS里一般使用arr[arr.length - 1], 又重复又有可能出现差一位的错误.

    const negativeArray = (els) => new Proxy(els, {
      get: (target, propKey, receiver) => Reflect.get(target,
        (+propKey < 0) ? String(target.length + +propKey) : propKey, receiver)
    });
    
    const unicorn = negativeArray(['?', '?', '?']);
    
    unicorn[-1] // '?'
    

    相关引用:

    TC39Array.lastItem的提案: proposal-array-last.

    Ruby的negative array indices: Ruby Quicktips.

    npm包: negative-array

    3. Hiding Properties

    我们经常将私有属性前面带上_,hide函数可以让前缀带有_的属性不可迭代.

    const hide = (target, prefix = '_') => new Proxy(target, {
      has: (obj, prop) => (!prop.startsWith(prefix) && prop in obj),
      ownKeys: (obj) => Reflect.ownKeys(obj)
        .filter(prop => (typeof prop !== "string" || !prop.startsWith(prefix))),
      get: (obj, prop, rec) => (prop in rec) ? obj[prop] : undefined
    })
    
    let userData = hide({
      firstName: 'Tom',
      mediumHandle: '@tbarrasso',
      _favoriteRapper: 'Drake'
    })
    
    userData._favoriteRapper        // undefined
    ('_favoriteRapper' in userData) // false
    Object.keys(userData)           // ['firstName', 'mediumHandle']
    

    可以使用Object.defineProperty设置属性或Symbol值设为属性使其不可迭代.

    4. Caching

    ephemeral函数可以设置属性多久超时. 超时时获取不到该属性值(缓存失效).

    const ephemeral = (target, ttl = 60) => {
      const CREATED_AT = Date.now()
      const isExpired = () => (Date.now() - CREATED_AT) > (ttl * 1000)
      
      return new Proxy(target, {
        get: (obj, prop) => isExpired() ? undefined : Reflect.get(obj, prop)
      })
    }
    
    let bankAccount = ephemeral({
      balance: 14.93
    }, 10)
    
    console.log(bankAccount.balance)    // 14.93
    
    setTimeout(() => {
      console.log(bankAccount.balance)  // undefined
    }, 10 * 1000)
    

    5. Enums & Read-Only Views

    枚举(enum)获取不存在的属性会报错, 他与第一个属性默认值类似, 返回的一个是默认值一个是报错, 但他的行为与枚举类型很相似所以单独列出来.

    const createEnum = (target) => readOnlyView(new Proxy(target, {
      get: (obj, prop) => {
        if (prop in obj) {
          return Reflect.get(obj, prop)
        }
        throw new ReferenceError(`Unknown prop "${prop}"`)
      }
    }))
    

    只读对象

    const NOPE = () => {
      throw new Error("Can't modify read-only view");
    }
    
    const NOPE_HANDLER = {
      set: NOPE,
      defineProperty: NOPE,
      deleteProperty: NOPE,
      preventExtensions: NOPE,
      setPrototypeOf: NOPE
    }
    
    const readOnlyView = target =>
      new Proxy(target, NOPE_HANDLER)
    
    let SHIRT_SIZES = createEnum({
      S: 10,
      M: 15,
      L: 20
    })
    
    SHIRT_SIZES.S // 10
    SHIRT_SIZES.S = 15
    
    // Uncaught Error: Can't modify read-only view
    
    SHIRT_SIZES.XL
    
    // Uncaught ReferenceError: Unknown prop "XL"
    

    相关链接

    TS enum type

    6. Operator Overload

    重载in运算符. 虽然有点感觉增加了心智负担, 但或许增加了代码可读性.

    const range = (min, max) => new Proxy(Object.create(null), {
      has: (_, prop) => (+prop >= min && +prop <= max)
    })
    
    const X = 10.5
    const nums = [1, 5, X, 50, 100]
    
    if (X in range(1, 100)) { // true
      // ...
    }
    
    nums.filter(n => n in range(1, 10)) // [1, 5]
    

    不止可以计算数字范围,还可以排除范围数, 自然数, 有理数, 虚数, 无限数等等.

    还可以重载delete, new.

    7. Cookies Object

    document.cookie获取的是一个字符串, 可以简单实现一个cookies的object方便操作.

    _octo=GH1.2.2591.47507; _ga=GA1.1.62208.4087; has_recent_activity=1
    
    const getCookieObject = () => {
        const cookies = document.cookie.split(';').reduce((cks, ck) => 
    	({[ck.substr(0, ck.indexOf('=')).trim()]: ck.substr(ck.indexOf('=') + 1), ...cks}), {});
        const setCookie = (name, val) => document.cookie = `${name}=${val}`;
        const deleteCookie = (name) => document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
    
        return new Proxy(cookies, {
    		set: (obj, prop, val) => (setCookie(prop, val), Reflect.set(obj, prop, val)),
            deleteProperty: (obj, prop) => (deleteCookie(prop), Reflect.deleteProperty(obj, prop))
         })
    }
    
    
    let docCookies = getCookieObject()
    
    docCookies.has_recent_activity              // "1"
    docCookies.has_recent_activity = "2"        // "2"
    delete docCookies["has_recent_activity"]   // true
    
    

    所以可以想到, 类似键值对的字符串都可以想是否需要用Proxy进行包装,来方便后续操作.

    总结

    为什么要用Proxy?

    个人的理解为:

    1. 增强代码的语义化, 改变原来对象对属性的各方面的操作, 而不去用额外的函数等去包裹, 包裹后的对象天生就对设置好的属性有特殊的操作.

    2. 可以用简单的配置将对象增强, 比如我们可以让cookie只读,隐藏特殊属性, 带有ZeroValue的时候可以这样写:

      // document.cookie = "_octo=GH1.2.2591.47507; _ga=GA1.1.62208.4087; has_recent_activity=1"
      
      let docCookies = withZeroValue(hide(readOnlyView(getCookieObject())), "Cookie not found")
      
      docCookies.has_recent_activity  // "1"
      docCookies.nonExistentCookie    // "Cookie not found"
      docCookies._ga                  // "Cookie not found"
      docCookies.newCookie = "1"      // Uncaught Error: Can't modify read-only view
      

    一句话总结Proxy的作用?

    可能会总结的并不完整,但最重要的作用就是增强对象.


    起源地下载网 » Proxy实际用法

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元