8_vue是如何進行資料代理的

2022-10-27 09:01:16

在瞭解了關於js當中的Object.defineProperty()這個方法後,我們繼續對vue當中的資料代理做一個基於現在的解析

建議觀看之前先了解下js當中的Obejct.defineProperty()

連結地址

瞭解如何代理

準備工作

  • 準備一個容器,供vue範例物件指定
  • 在範例物件當中設定供頁面呼叫的資料(data)
  • 測試頁面
<body>
    <!-- 準備一個容器 -->
    <div class="subject">
        <div>暱稱:{{name}}</div>
        <div>電話:{{phone}}</div>
    </div>
</body>
<script>
    new Vue({
        el: '.subject',
        data: {
            name: 'wavesbright',
            phone:"134****2557"
        }
    });
</script>

檢視VM

  • 通過之前的複習,我們知道,在vm這個範例物件當中
  • 設定項data當中的屬性,會掛載到vm上,供頁面呼叫
  • 而滑鼠懸停在二者身上,出現了 invoke property getter,說明什麼?
  • 說明,vm上的name和phone,是通過defineProperty 新增上去的 === 做了資料代理

和誰做了資料代理?

  1. 當你存取 name 或者 phone的時候
  2. 一定會呼叫get(getter),這個get 一定會從某個地方,將所需要的值進行 返回
  3. 什麼地方? data嘛
  4. 那你要對 name 和 phone 進行修改的時候,那肯定要 呼叫set嘛
  5. 如何確定呢?

get和set

確實有,在哪裡呢,往下翻就可以看到

這不就是代理麼

驗證兩條線

vm當中的name 與 phone 是 與data進行資料繫結的

get

  1. 既然繫結了,那當我存取name變數的時候
  2. 先呼叫get
  3. get 返回 data.name當中設定的value值

驗證過程

很簡單,直接修改data.name的值不就知道了

原圖

修改後

說明是繫結到一起的嘛,但我為什麼不修改 vm.name的值去檢視data是否發生改變了呢?

問題引出1

  • 我們設計的data當中的屬性,經過vue的一系列操作
  • 最終掛載到了vue範例上,實現了資料繫結
  • 資料繫結是一個事實,我們現在所做的是驗證這個過程
  • 通過修改設定項 data當中的name屬性,頁面當中確實發生了變化
  • 但是我現在想驗證的是,我修改 vm.name的值的時候,data如何確定變化

vm.data檢視就能完成了,這不很簡單嘛?是嗎?

開國際玩笑哦,你data在全域性定義了嗎?沒有吧?vm當中為什麼也沒有data呢?

set

解決方式1

定義一個全域性的data不就行了

驗證一下嘛,修改vue當中的name屬性,data是否會發生變化

確實可以

問題衍生2

那麼又有一個問題,我這個全域性data是自己定義的,而正常構建的vue範例物件可不會這麼寫

但事實情況就是,我修改設定項data當中的資料,可以影響頁面,而修改頁面也可以影響data

我辛辛苦苦設定了一個data物件,交給了vm,vm如果不把我這個data存下來,那人家以後要用屬性去那裡取?vm一定會把這個data留下來。

這就說明一個問題,設定項data,一定在 構建完成的這個範例物件vm身上,但是為什麼找不到呢?

因為人家叫 vm._data

這個就不展開了,因為 vm當中的data除了做資料代理,還有資料劫持

我們當下只需要記住一點,vm._data === data

驗證set的過程

這是當前頁面,現在我們要修改name屬性

修改成全大寫

分析過程

  1. 我們修改了vm.name的值
  2. 一定呼叫了 set函數,拿到這個value值
  3. 並且將這個 value值賦給了vm._data(data)

圖文解析

第一部分

一切的一切都是因為開頭寫了這段程式碼

緊隨其後,馬上就給我們建立了一個vue的範例物件

然後,vue開始為vm這個範例物件準備一些東西(屬性)

重點,data來了,完全來自於上方的設定項data

截止到目前來說,沒有資料代理的存在。我們所寫的data,就是單純的進行了一次賦值,然後給了下劃線data(_data)

第二部分

實際上,vue做到這一步已經差不多了,程式碼也是可以寫下去的

但是,請問,目前vm身上,有name嗎,沒有

但是我能拿到name的值嗎?可以的,因為我有 _data

一樣可以拿到name和phone的值

因為,vm這個物件身上的所有屬性,在模板上面都能夠直接使用

但是這樣寫,那不是直接崩潰,建立一個變數就需要 _data一次,vue在這裡做了一個很棒的操作

也就是資料代理

第三部分

  1. vm在自己身上建立了一個變數name
  2. 什麼方式建立的?defineProperty
  3. 通過get拿到vm自身上的_data.name的值
  4. 修改資料的時候通過set,獲取value,然後再將_data當中的屬性進行修改
  5. 完成了資料代理,雙向繫結

為什麼要將data當中的資料放在vm身上一份呢(_data)

就是為了讓你編碼的時候更方便(不至於每次都是 _data.xxx

總結

  1. vue中的資料代理
    • 通過vm物件 來 代理 data物件(設定項)中的屬性操作(get/set
  2. Vue中資料代理的好處
    • 更加方便操作data中的資料(_data.xxx)
  3. 基本原理
    1. 通過Object.defineProperty()將data設定項當中的所有屬性設定到vm物件上
    2. 為每一個新增到vm上的屬性,指定一個get和set函數(getter/setter)
    3. 在getter/setter內部去操作(讀/寫),data中對應的屬性

展開_data

思考

老師不讓展開是對的

因為如果按照之前的理解,這個符號代表什麼 (...) 代表資料代理

這樣容易引起理解誤區,,這裡實際上並不是資料代理,而是做了一個資料劫持

我希望看到的 _data的展開內容是什麼?是這樣的

實際上並不是

vue的承諾

只要你敢修改data當中的屬性值,我就敢在頁面當中 {{property}}一起發生變化

  1. name的值發生了改變,最終影響到的是誰 === _data.name
  2. 那麼頁面元素是怎麼同步進行修改的?
  3. vue是不是必須要知道,name這裡發生了改變,他需要做什麼 === 監聽
  4. 經歷了一系列變動後,完成了小小的升級,最終達成響應式操作