<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JavaScript的Proxy代理對(duì)象,看完你就會(huì)了

          共 2661字,需瀏覽 6分鐘

           ·

          2021-06-16 12:15


          什么是Proxy代理?

          // pOjb就是通過(guò)new Proxy創(chuàng)建的代理對(duì)象var pObj = new Proxy(obj, handlers)

          為什么需要代理對(duì)象

          舉個(gè)記賬的例子:

          // obj代表我們,wallet屬性指我們錢包,現(xiàn)在我們錢包里有100元// consume指消費(fèi)次數(shù),每次消費(fèi)加1, 記一筆賬var obj = {wallet: 100}var consume = 0
          // 這個(gè)月,我們喝了五次肥宅快樂水,每次消費(fèi)我們都記一筆
          // 今天消費(fèi)3元consume++obj.wallet = 97
          // 今天消費(fèi)3元consume++obj.wallet = 94
          // 今天消費(fèi)3元consume++obj.wallet = 91
          // 今天消費(fèi)3元consume++obj.wallet = 88
          // 今天消費(fèi)3元consume++obj.wallet = 85

          每次我們修改錢包剩余金額時(shí),都要執(zhí)行一次consume++去執(zhí)行一次記賬的操作。有沒有更簡(jiǎn)單的方式,不需要每次都寫上一行代碼去增加消費(fèi)次數(shù)呢?

          答案當(dāng)然有,它就是Proxy代理對(duì)象!使用代理對(duì)象,你想對(duì)目標(biāo)對(duì)象的屬性操作全部改為對(duì)代理對(duì)象相同屬性的操作,代理對(duì)象提供了對(duì)屬性獲取 [[get]] 修改 [[set]] 等操作的攔截,js將這種攔截稱為trap(捕捉器)。

          通過(guò)捕捉器,我們就可以捕獲到 代碼中對(duì)屬性的操作時(shí)機(jī),讓我們能夠先執(zhí)行我們自定義的業(yè)務(wù)邏輯代碼。

          因?yàn)槲覀儗?duì)目標(biāo)對(duì)象的屬性操作改為了對(duì)代理對(duì)象相同的屬性操作,所以我們?cè)谧詈笮枰ㄟ^(guò)Reflact執(zhí)行目標(biāo)對(duì)象的原始操作。

          var consume = 0// 目標(biāo)對(duì)象var obj = {wallet: 100}// 捕獲器trapvar handlers = {  set(target, key, val) {    // target 目標(biāo)對(duì)象    // key 代理對(duì)象要修改的屬性        // 記錄一筆消費(fèi)    consume++    // 通過(guò)Reflact對(duì)象觸發(fā)原始目標(biāo)對(duì)象的屬性操作    // 相當(dāng)于執(zhí)行 target[key] = val    Reflect.set(target, key, val)  }}// 代理對(duì)象var pObj = new Proxy(obj, handlers)// 將對(duì)目標(biāo)對(duì)象obj的屬性wallet操作改為代理對(duì)象相同屬性wallet的操作pObj.wallet = 97pObj.wallet = 94pObj.wallet = 91pObj.wallet = 88pObj.wallet = 85
          console.log(obj.wallet) // 85console.log(consume) // 5

          如何取消代理

          假如某一天,你實(shí)現(xiàn)了財(cái)務(wù)自由,不需要再精打細(xì)算記錄每一筆消費(fèi)了,你可能就需要取消此前的代理,代碼很簡(jiǎn)單,往下看:

          var consume = 0var obj = {wallet:  100}var handlers = {  set(target, key, val) {    consume++    Reflect.set(target, key, val)  }}
          // 使用Proxy.revocable創(chuàng)建代理var tmpObj = Proxy.revocable(obj, handlers)var pObj = tmpObj.proxyvar prevoke = tmpObj.revoke
          // 使用代理對(duì)象進(jìn)行消費(fèi)記賬pObj.wallet = 97pObj.wallet = 94pObj.wallet = 91
          // 某一天,我們實(shí)現(xiàn)了一個(gè)小目標(biāo)pObj.wallet = 100000000// 我們不需要記賬了,我們需要取消創(chuàng)建的代理prevoke() // 執(zhí)行prevoke即可,就是這么簡(jiǎn)單 哦耶~
          pObj.wallet = 99999997 // TypeError 報(bào)錯(cuò)啦 (代理取消之后就不能使用了喲!)

          代理在后模式

          前面的示例都是先執(zhí)行代理捕獲器中的業(yè)務(wù)邏輯,最后再通過(guò)Reflect執(zhí)行目標(biāo)對(duì)象的屬性操作,這種捕獲代碼操作在前,目標(biāo)對(duì)象操作在后的模式稱為“代理在先”模式,有在先,當(dāng)然就有在后模式。

          當(dāng)然這里的“代理在后”模式并不是先使用Reflect對(duì)象觸發(fā)目標(biāo)對(duì)象屬性操作,在執(zhí)行捕獲器中的其他操作代碼。

          而是指代理作為目標(biāo)對(duì)象的一種補(bǔ)充,我們?nèi)匀徊僮鞯氖悄繕?biāo)對(duì)象,只是當(dāng)某些操作在目標(biāo)對(duì)象上無(wú)法實(shí)現(xiàn)時(shí),才使用代理對(duì)象。

          等會(huì),當(dāng)某些操作目標(biāo)對(duì)象無(wú)法提供時(shí),js會(huì)向目標(biāo)對(duì)象的原型prototype上進(jìn)行查找,所以“代理在后”模式是對(duì)目標(biāo)對(duì)象的原型進(jìn)行代理!

          var handlers = {  get(target, key, context) {    return function () {      context.speak(key + '!')    }  }}
          var catchall = new Proxy({}, handlers)
          var greeter = { speak(who = 'someone') { console.log('hello ', who) }}
          // 將catchall設(shè)置為greeter的原型Object.setPrototypeOf(greeter, catchall)
          greeter.speak() // hello someonegreeter.speak('world') // hello world
          // 執(zhí)行g(shù)reater上不存在的方法greeter.everyone() // hello everyone!

          Reflect

          Reflect對(duì)象用來(lái)觸發(fā)目標(biāo)對(duì)象執(zhí)行相應(yīng)的操作,就是這么簡(jiǎn)單!

          Reflect.get(target, key, context) // 等價(jià)于  target[key]Reflect.set(target, key, val) // 等價(jià)于 target[key] = val

          本文完~

          學(xué)習(xí)更多技能

          請(qǐng)點(diǎn)擊下方公眾號(hào)

          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天天天天天色 | 成人网站欧美 | 豆花视频在线看成人网站 | 啊啊啊啊啊www. | 丁香五月激情中文 |