摘要
我們都知道Vue的響應(yīng)式是通過Object.defineProperty來進(jìn)行數(shù)據(jù)劫持。但是那是針對Object類型可以實現(xiàn), 如果是數(shù)組呢? 通過set/get方式是不行的。
但是Vue作者使用了一個方式來實現(xiàn)Array類型的監(jiān)測: 攔截器。
核心思想
通過創(chuàng)建一個攔截器來覆蓋數(shù)組本身的原型對象Array.prototype。
攔截器
通過查看Vue源碼路徑vue/src/core/observer/array.js。
/** * Vue對數(shù)組的變化偵測 * 思想: 通過一個攔截器來覆蓋Array.prototype。 * 攔截器其實就是一個Object, 它的屬性與Array.prototype一樣。 只是對數(shù)組的變異方法進(jìn)行了處理。*/function def (obj, key, val, enumerable) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, writable: true, configurable: true })}// 數(shù)組原型對象const arrayProto = Array.prototype// 攔截器const arrayMethods = Object.create(arrayProto)// 變異數(shù)組方法:執(zhí)行后會改變原始數(shù)組的方法const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']methodsToPatch.forEach(function (method) { // 緩存原始的數(shù)組原型上的方法 const original = arrayProto[method] // 對每個數(shù)組編譯方法進(jìn)行處理(攔截) def(arrayMethods, method, function mutator (...args) { // 返回的value還是通過數(shù)組原型方法本身執(zhí)行的結(jié)果 const result = original.apply(this, args) // 每個value在被observer()時候都會打上一個__ob__屬性 const ob = this.__ob__ // 存儲調(diào)用執(zhí)行變異數(shù)組方法導(dǎo)致數(shù)組本身值改變的數(shù)組,主要指的是原始數(shù)組增加的那部分(需要重新Observer) let inserted switch (method) { case 'push': case 'unshift': inserted = args break case 'splice': inserted = args.slice(2) break } // 重新Observe新增加的數(shù)組元素 if (inserted) ob.observeArray(inserted) // 發(fā)送變化通知 ob.dep.notify() return result })})關(guān)于Vue什么時候?qū)ata屬性進(jìn)行Observer
如果熟悉Vue源碼的童鞋應(yīng)該很快能找到Vue的入口文件vue/src/core/instance/index.js。
function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options)}initMixin(Vue)// 給原型綁定代理屬性$props, $data// 給Vue原型綁定三個實例方法: vm.$watch,vm.$set,vm.$deletestateMixin(Vue)// 給Vue原型綁定事件相關(guān)的實例方法: vm.$on, vm.$once ,vm.$off , vm.$emiteventsMixin(Vue)// 給Vue原型綁定生命周期相關(guān)的實例方法: vm.$forceUpdate, vm.destroy, 以及私有方法_updatelifecycleMixin(Vue)// 給Vue原型綁定生命周期相關(guān)的實例方法: vm.$nextTick, 以及私有方法_render, 以及一堆工具方法renderMixin(Vue)export default Vue
新聞熱點
疑難解答
圖片精選