動手寫寫Vue的資料劫持

2021-10-03 22:12:56 字數 2501 閱讀 2052

週末開寫, ig nb!

這裡學習的是vue 2.x下雙向繫結的方法,是 資料劫持 + 訂閱發布者模式。用object.defineproperty(obj,prop,descriptor)方法去繫結data中的值,然後在發現值變化的時候觸發更新函式,去更新檢視。

object.

defineproperty

(obj,key,descriptor)

`obj`

: 目標物件。

`key`

: 需要定義的屬性或方法的名稱。

`descriptor`

: 目標屬性所擁有的特性。

`descriptor`

有以下的屬性:

// 1. value: 屬性的值

// 2. writable: 如果為false,屬性的值就不能被重寫。

// 3. get: 一旦目標屬性被訪問就會調回此方法,並將此方法的運算結果返回使用者。

// 4. set: 一旦目標屬性被賦值,就會調回此方法。

// 5. configurable: 可否被修改,如果為false,writable, configurable, enumerable 就不能改。

// 6. enumerable: 是否可被列舉,就是在迴圈或者 keys 的時候是不是可以被遍歷到。

let data =

object.

keys

(data)

.foreach

(key=>

,set

:function()

})})

console.

log(data.name)

// get

data.name =

'test'

// name changed

上面對data的值進行了監聽,在set函式裡,當資料變化,對其有操作就可以被監聽到,然後就可以對資料檢視做出改變。但是同時也存在乙個問題,當資料被初始化的時候,系統對每個資料進行了訂閱和監聽,如果後期在物件上加乙個屬性,那麼就不會被監聽到,所以需要使用vue.set()

為了完成了資料的』可觀測』,我們需要建立乙個依賴收集容器,用來容納所有的「訂閱者」,我們就可以在資料被使用的時候通知那些依賴該資料的檢視更新了,一旦資料發生變化,就統一通知更新。建立訊息訂閱器dep:

function

dep(

)// 判斷是否增加訂閱者

self.

depend

=function()

}// 通知試圖更新

self.

notify

=function()

)}}

然後我們把資料劫持和新增訂閱改造下並封裝成個函式:

function

definereactive

(data, key, val)

,set

(newval)})

}function

observable

(data)

let keys = object.

keys

(data)

; keys.

foreach

((key)

=>

)return data;

}

訂閱者watcher在初始化的時候需要將自己新增進訂閱器dep中,那該如何新增呢?我們已經知道***observer是在get函式執行了新增訂閱者watcher的操作的,所以我們只要在訂閱者watcher初始化的時候觸發對應的get函式去執行新增訂閱者操作即可,那要如何觸發get的函式,再簡單不過了,只要獲取對應的屬性值就可以觸發了,核心原因就是因為我們使用了object.defineproperty( )進行資料監聽。這裡還有乙個細節點需要處理,我們只要在訂閱者watcher初始化的時候才需要新增訂閱者,所以需要做乙個判斷操作,因此可以在訂閱器上做一下手腳:在dep.target上快取下訂閱者,新增成功後再將其去掉就可以了。訂閱者watcher的實現如下:

function

watcher

(vm, exp, cb)

} self.

get=

function()

}

大概的流程就是,我們用object.defineproperty( )設定乙個***,用來監聽所有的屬性,如果發生了變化就通知訂閱者,是不是要更新,然後通過訂閱器來同意管理訂閱者。

自己動手寫Vue外掛程式Toast

避免重複install,設立flag toast.installed false toast.install function vue,options 使用options的配置 for let i in options vue.prototype.toast toast,type 2 建立例項,掛載...

vue 資料劫持

其實,並沒有這麼 神奇 的事,資料劫持的核心就是在 物件的身上重新定義被 物件所有可列舉屬性,並設定 getter 和 setter 監視著它的變化,然而實現這個核心功能就是乙個方法 object.defineproperty 通過該方法在例項物件上重新定義了和data物件裡面的所有屬性,然而就實現...

手寫Vue 1 物件劫持

1.引入我們手寫的vue 拿到配置資料 import vue from source src index let vm new vue arr 1,2,3 computed watch console.log vm settimeout 1000 2.新建檔案 source src index 在這...