<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>

          Vue 源碼解析(Reflect and Proxy)

          共 5447字,需瀏覽 11分鐘

           ·

          2021-03-08 21:59

          作者:夏灬影
          來(lái)源:SegmentFault 思否社區(qū)




          最近研究 vue3 源碼, 知道使用了 Proxy 和 Reflect, 但是不了解它們之間的關(guān)系


          這篇文章主要是讓大家了解 vue3 為什么使用 Proxy 和 Reflect 以及響應(yīng)式的部分原理




          為什么使用 Proxy(Proxy 和 Object.defineproperty)


          Object.defineproperty實(shí)現(xiàn)對(duì)象監(jiān)聽(tīng)


          先解析一下vue2中使用的Object.defineproperty


          let obj = {
              a: 10
          }
          Object.keys(obj).forEach(key => {
              let value = obj[key]
              Object.defineProperty(obj, key, {
                  set(newValue) {
                      console.log(`監(jiān)聽(tīng)${key}改變: ${newValue}`);
                      value = newValue
                  },
                  get() {
                      console.log(`獲取${key}對(duì)應(yīng)的值: ${value}`);
                      return value
                  }
              })
          })
          obj.a = 100 // 監(jiān)聽(tīng)a改變: 100
          obj.b = 10 // 不會(huì)被監(jiān)聽(tīng)到


          通過(guò)上面的例子我們可以看到obj新添加的屬性b, 并不會(huì)被監(jiān)聽(tīng)到


          vue2中使用中我們也會(huì)遇到這樣的問(wèn)題


          # template
          <p @click="adda(obj)">{{ obj.a }}</p>
          <p @click="addb(obj)">{{ obj.b }}</p>

          # srcript
          data () {
              return {
                  obj:{
                      a:1
                  }
              }
          },
          mounted () {
              this.obj.b = 1;
          },
          methods: {
              addb(item){
                  item.b += 1;
                  console.log(this.obj.b)
              },
              adda(item){
                  item.a += 1;
              }
          }


          我們發(fā)現(xiàn)點(diǎn)擊obj.a是響應(yīng)式, 頁(yè)面也會(huì)更新


          而新增的obj.b點(diǎn)擊則不會(huì)


          因?yàn)関ue2使用的Object.defineproperty無(wú)法監(jiān)聽(tīng)到新增的對(duì)象屬性


          針對(duì)這個(gè)問(wèn)題vue2提供了$set方法來(lái)解決


          mounted () {
              this.$set(this.obj, "b", 1)
          }


          Proxy實(shí)現(xiàn)對(duì)象監(jiān)聽(tīng)


          let obj = {
              a: 10
          }
          const handler = {
              get(target, prop) {
                  console.log(`獲取${prop}對(duì)應(yīng)的值: ${target[prop]}`);
                  return target[prop];
              },
              set(target, prop, val) {
                  target[prop] = val;
                  console.log(`監(jiān)聽(tīng)${prop}改變: ${val}`);
                  return true
              }
          }

          let obj2 = new Proxy(obj, handler)
          obj2.b = 100 // 監(jiān)聽(tīng)b改變: 100


          我們可以看到通過(guò)Proxy實(shí)例可以對(duì)新添加的屬性進(jìn)行監(jiān)聽(tīng)


          當(dāng)然Proxy還可以做許多的其他功能, 這里就不多介紹了


          我查看Vue3的源碼的時(shí)候一直對(duì)Proxy中使用的Reflect感到不解,為什么要使用Reflect.get和Reflect.set, 我查詢了一些文章, 大概了一下思路


          Reflect


          我將通過(guò)一些問(wèn)題, 來(lái)指明Reflect中Proxy中的用處


          我們有一個(gè)user帶有_name屬性的對(duì)象和一個(gè)吸氣劑。


          這是圍繞它的代理:


          let user = {
            _name: "Guest",
            get name() {
              return this._name;
            }
          };

          let userProxy = new Proxy(user, {
            get(target, prop, receiver) {
              return target[prop];
            }
          });

          console.log(userProxy.name); // Guest


          對(duì)于我們的示例而言,這就足夠了。


          一切似乎都還好。但是,讓我們將示例變得更加復(fù)雜。


          繼承另一個(gè)對(duì)象后admin從user,我們可以觀察到不正確的行為:


          llet user = {
            _name: "Guest",
            get name() {
              return this._name;
            }
          };

          let userProxy = new Proxy(user, {
            get(target, prop, receiver) {
              console.log(target) // user對(duì)象{_name: "Guest"}
              return target[prop];
            }
          });

          let admin = {
            __proto__: userProxy,
            _name: "Admin"
          };

          console.log(admin.name); // Guest


          閱讀admin.name應(yīng)該返回"Admin",而不是"Guest"!


          怎么了?也許我們?cè)诶^承方面做錯(cuò)了什么?


          問(wèn)題實(shí)際上出在代理所在的行中:


          1. 當(dāng)我們閱讀時(shí)admin.name,由于admin對(duì)象沒(méi)有自己的屬性,搜索將轉(zhuǎn)到其原型。
          2. 原型是userProxy
          3. name從代理讀取屬性時(shí),其get將觸發(fā)并從原始對(duì)象中返回該屬性,它在上下文中運(yùn)行其代碼this=target。因此,結(jié)果this._name來(lái)自原始對(duì)象target,即:from user。

          而這個(gè)時(shí)候就是Reflect.get就派上用場(chǎng)了

          如果我們使用它,一切都會(huì)正常運(yùn)行。

          let user = {
            _name: "Guest",
            get name() {
              return this._name;
            }
          };

          let userProxy = new Proxy(user, {
            get(target, prop, receiver) { // receiver = admin
              return Reflect.get(target, prop, receiver);
            }
          });


          let admin = {
            __proto__: userProxy,
            _name: "Admin"
          };

          console.log(admin.name); // Admin

          Reflect.get中receiver參數(shù),保留了對(duì)正確引用this(即admin)的引用,該引用將Reflect.get中正確的對(duì)象使用傳遞給get。



          點(diǎn)擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開(kāi)更多互動(dòng)和交流,掃描下方”二維碼“或在“公眾號(hào)后臺(tái)回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

          - END -


          瀏覽 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>
                  国产精品 - 色哟哟 | 天堂网av手机版 天堂在线一区二区 | 亚洲综合无码一区二区毛片 | 国产熟妇毛多 久久久久一区 | 日韩精品 A片视频 |