在瀏覽一篇博文的時候,看到裡面提到了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框架出發,探索其中資料劫持的奧秘 本文所選取的...