vue中的資料劫持

2021-10-09 06:34:23 字數 3155 閱讀 9361

在瀏覽一篇博文的時候,看到裡面提到了vue中資料劫持的概念,之前只是知道有這個東西,知道這個東西是vue的核心之一,是實現資料雙向繫結的重要原理,但並未深入研究,那麼今天就借這篇文章學習整理一下vue中的資料劫持到底是什麼。

在面經中最常見的問題之一就是,你知道雙向繫結嗎,知道什麼是mvvm嗎?

學術性的回答模板有很多,其實簡單來說就是資料和檢視其中一方做出修改,另一方也隨之變動。檢視能夠驅動資料,資料也能驅動檢視。

檢視驅動資料可以通過事件繫結來實現,那麼資料驅動檢視呢?

方法就是,給資料新增監聽,一旦資料發生變化,就執行檢視的修改操作,這個過程就是資料劫持

一段簡單的vue**

"message"

>

}<

/p>

<

/div>

<

/template>

export

default;}

};<

/script>

那麼vue中的資料劫持究竟是怎麼實現的呢?

其實就是通過object.defineproperty

先來了解一下object.defineproperty

object.defineproperty()方法會直接在乙個物件上定義乙個新屬性,或者修改乙個物件的現有屬性,並返回此物件。

語法:

object.

defineproperty

(obj, prop, descriptor)

引數:

obj: 要定義屬性的物件。

prop:要定義或修改的屬性的名稱或symbol

descriptor:要定義或修改的屬性描述符。

物件裡目前存在的屬性描述符有兩種主要形式:資料描述符和訪問描述符。資料描述符是乙個具有值的屬性,該值可以是可寫的,也可以是不可寫的。訪問描述符是由getter函式和setter函式所描述的屬性。乙個描述符只能是這兩者其中之一;不能同時是兩者。

var message =

'hello world'

;const data =

;object.

defineproperty

(data,

'message',,

set(newval)})

;data.message // 'hello world'

data.message =

'test'

// 'test'

那麼在vue2.x中,要想實現data中所有屬性都實現資料劫持,就要先遍歷data中的所有屬性,對每乙個屬性都使用object.defineproperty,當屬性的值發生變化時,就執行檢視渲染操作。

參考乙個vue資料劫持的簡單實現(原理示例,非原始碼)

const data =

, numbers:[1

,2,3

,4]}

observerobject中對傳入的每乙個屬性使用object.defineproperty進行監聽,如果傳入的是乙個物件則遞迴呼叫observe遍歷物件的每乙個屬性,確保data中的所有屬性都加入監聽。

function

observerobject

(target, name, value)

object.

defineproperty

(target, name,

,set

(newval)

value = newval

}renderview()

//模擬檢視渲染操作}}

)}

observe中遍歷物件中的所有屬性。

function

observer

(target)

for(

const key in target)}}

observer

(data)

可以看到,由於object.defineproperty每次只能設定乙個具體的屬性,因此需要進行遞迴遍歷操作,如果資料層級很深,就會造成效能隱患。

另外,object.defineproperty只能作用在物件上,那麼對於陣列資料應該如何處理呢?

陣列其實也可以看作一宗特殊的物件,其下標就是對應的屬性,理論上也可以使用object.defineproperty進行資料劫持,但在vue中並沒有選擇這麼做。而是選擇劫持一些陣列的常用操作方法,通過修改陣列的原型方法,達到監聽陣列資料變化的目的。

//不能直接篡改array.prototype物件,這樣會對所有的陣列例項都產生影響,需要通過原型繼承得到乙個新的原型物件

const oldarrayproperty = array.prototype

const newarrayproperty = object.

create

(oldarrayproperty)

const methods =

['pop'

,'push'

,'shift'

,'unshift'

,'splice'

,'sort'

,'reverse'

]methods.

foreach

((method)

=>})

// 在observer函式中加入陣列的判斷,如果傳入的是陣列,則改變陣列的原型物件為我們修改過後的原型。

if(array.

isarray

(target)

)

在vue3版本中,選擇使用了proxy去實現物件的監聽,避免了一些object.defineproperty方法本身帶來的問題。

vue 資料劫持

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

vue 中 陣列劫持

vue中物件劫持 object.defineproperty obj,prop,descriptor 1 obj 必需。目標物件 2 prop 必需。需定義或修改的屬性的名字 3 descriptor 必需。目標屬性所擁有的特性 這個介紹的比較多,就不展開了。vue中陣列劫持 劫持push方法 le...

Vue核心之資料劫持

當前前端界空前繁榮,各種框架橫空出世,包括各類mvvm框架橫行霸道,比如anglar,regular,vue,react等等,它們最大的優點就是可以實現資料繫結,再也不需要手動進行dom操作了,它們實現的原理也基本上是髒檢查或資料劫持。那麼本文就以vue框架出發,探索其中資料劫持的奧秘 本文所選取的...