在Vue中,可以使用watch來監(jiān)聽特定數(shù)據(jù)的變化,但如果需要監(jiān)聽一個數(shù)組的變化,就需要使用Vue提供的特殊數(shù)組方法,比如push、splice等。但是這些方法只能監(jiān)聽部分變化,而且在使用時需要注意一些奇怪的情況。所以Vue提供了另外一種方法,即用Object.defineProperty()來監(jiān)測數(shù)組變化。
Object.defineProperty()是ES5提供的一個方法,可以監(jiān)聽某個對象屬性的變化。那么,Vue中的數(shù)組監(jiān)聽就是通過重寫數(shù)組原型上的push、pop、shift、unshift、splice、sort、reverse這七個方法來實現(xiàn)了。
//重寫數(shù)組的原型方法,監(jiān)測數(shù)組變化 const arrayProto = Array.prototype //復(fù)制一份原型方法,用于修改 const arrayMethods = Object.create(arrayProto) //要改變的7個數(shù)組方法 const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] methodsToPatch.forEach(function (method) { //緩存原型上的方法 const original = arrayProto[method] //把重寫后的方法掛載到數(shù)組對象上 def(arrayMethods, method, function mutator (...args) { //調(diào)用原始的方法 const result = original.apply(this, args) const ob = this.__ob__ //添加新元素需要觸發(fā)更新 ob.dep.notify() return result }) })
上述代碼通過forEach循環(huán),把要修改的7個方法復(fù)制了一份,并修改了其中push、unshift、splice這三個方法。這三個方法都是在插入元素時會發(fā)生變化,所以這里需要在這些方法的最后添加對數(shù)據(jù)的變化通知,進(jìn)而觸發(fā)更新。
關(guān)于缺陷,使用Vue提供的特殊數(shù)組方法監(jiān)聽也會有一些問題。比如通過索引修改數(shù)組元素時無法監(jiān)聽,更改數(shù)組長度時也無法監(jiān)聽。而使用上述方法重寫原型方法來監(jiān)聽數(shù)組變化,需要考慮到原型方法可能被污染,不同環(huán)境下可能無法保證兼容。因此,Vue在實現(xiàn)數(shù)組監(jiān)聽時,并不是只使用一種方法,而是采用了一些技巧來確保在不同環(huán)境下都能夠保證監(jiān)聽的可靠性。
總而言之,Vue中的數(shù)組監(jiān)聽機(jī)制是通過重寫數(shù)組的原型方法來完成的。使用此方法可以完全監(jiān)聽數(shù)組的變化,而不僅僅是特定的一些情況。同時,Vue通過多種方式來解決不同環(huán)境下監(jiān)聽機(jī)制的缺陷,保證了監(jiān)聽的可靠性。