淺談Vue數(shù)據(jù)響應(yīng)思路之?dāng)?shù)組
之前梳理Vue數(shù)據(jù)響應(yīng)思路 時沒有考慮數(shù)組的情況。
js 中數(shù)組有很多實(shí)例方法,其中有一部分會改變數(shù)組本身的值,比如 push pop shift unshift 等,這些方法被稱為變異方法,這些變異方法也是 Vue 開發(fā)中常用的數(shù)組操作方法。那么要實(shí)現(xiàn)對數(shù)組的觀測,首先要考慮的就是如何截獲這些變異方法的調(diào)用。
簡單來說,Vue 是通過保持這些數(shù)組變異方法原有功能不變的前提下,對其功能進(jìn)行擴(kuò)展來實(shí)現(xiàn)攔截的。具體怎么操作,可以先看一下例子:
function add10(num) { return num + 10 } console.log(add10(5)) // 15 const originalAdd10 = add10 add10 = function(num) { console.log('截獲了add10操作') return originalAdd10(num) } console.log(add10(5)) // '截獲了add10操作' // 15
該例中,首先使用變量 originalAdd10 緩存 add10 函數(shù),再重新定義 add10 函數(shù),在重新定義的函數(shù)體里就可以執(zhí)行額外增加的功能,比如上例中的 console.log('截獲了add10操作'),然后執(zhí)行緩存的 add10 函數(shù)即 originalAdd10,并將結(jié)果返回,原理大抵如此。
那么,具體可實(shí)現(xiàn)如下:
const mutationMethods = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] const arrayMethods = Object.create(Array.prototype) const arrayProto = Array.prototype mutationMethods.forEach(method => { arrayMethods[method] = function (...args) { const result = arrayProto[method].apply(this, args) console.log(`我截獲了對數(shù)組的${method}操作`) return result } }) const arr = ['kobe', 'jordan'] arr.__proto__ = arrayMethods arr.push('harden') // '我截獲了對數(shù)組的push操作' console.log(JSON.stringify(arr)) // '["kobe","jordan","harden"]'
以上,mutationMethods 是所有要攔截的數(shù)組變異方法的集合。
整體思路就是通過設(shè)置數(shù)組對象的 __proto__ 屬性的值為一個新對象 arrayMethods,以代理數(shù)組 mutationMethods 中的變異方法,并將 arrayMethods 的原型設(shè)置為數(shù)組構(gòu)造函數(shù)本來的原型,這樣方能保證除卻代理的方法以外,不影響數(shù)組本身的其它方法和屬性。
其中:
const arrayMethods = Object.create(Array.prototype)
以上實(shí)現(xiàn)了 arrayMethods 的原型是數(shù)組構(gòu)造函數(shù)本來的原型,即 arrayMethods.__proto__ === Array.prototype。
緊接著:
const arrayProto = Array.prototype
這句使用 arrayProto 變量緩存了 Array.prototype。
再然后:
mutationMethods.forEach(method => { arrayMethods[method] = function (...args) { const result = arrayProto[method].apply(this, args) console.log(`我截獲了對數(shù)組的${method}操作`) return result } })
將 mutationMethods 進(jìn)行循環(huán),在 arrayMethods 對象上以 mutationMethods 中各元素為 key,即方法名,定義作為攔截器的同名變異方法。
具體:
const result = arrayProto[method].apply(this, args)
執(zhí)行緩存的 Array.prototype,即 arrayProto 中對應(yīng)的變異方法,并傳入 this 以及 args,也就是將來調(diào)用該方法的數(shù)組對象,和調(diào)用該方法時傳入的參數(shù)(或參數(shù)列表)轉(zhuǎn)化成的參數(shù)數(shù)組,并將結(jié)果給到變量 result。
這里使用了解構(gòu)賦值的方式將參數(shù)(或參數(shù)列表)轉(zhuǎn)化成了參數(shù)數(shù)組,這么做是因?yàn)椴荒艽_定參數(shù)的個數(shù),所以只能使用 apply(不能用 call),并傳入?yún)?shù)數(shù)組。
之后:
console.log(`我截獲了對數(shù)組的${method}操作`)
也就是攔截之后要額外執(zhí)行的操作了。
最后:
return result
將數(shù)組原變異方法執(zhí)行的結(jié)果返回,保證原有功能不受影響。
forEach 執(zhí)行完之后:
const arr = ['kobe', 'jordan'] arr.__proto__ = arrayMethods
聲明并初始化 arr,并將 arr 的 __proto__ 指向 arrayMethods,這樣便代理了 mutationMethods 中的變異方法。
最終:
arr.push('harden') // '我截獲了對數(shù)組的push操作' console.log(JSON.stringify(arr)) // '["kobe","jordan","harden"]'
數(shù)組對象手動擴(kuò)展的功能以及原功能均正常,實(shí)現(xiàn)了數(shù)組變異方法的攔截。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于vue實(shí)現(xiàn)一個神奇的動態(tài)按鈕效果
今天我們將利用vue的條件指令來完成一個簡易的動態(tài)變色功能按鈕,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友參考下吧2019-05-05vue實(shí)現(xiàn)div可拖動位置也可改變盒子大小的原理
這篇文章主要介紹了vue實(shí)現(xiàn)div可拖動位置也可改變盒子大小,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09element-ui+vue-treeselect下拉框的校驗(yàn)過程
這篇文章主要介紹了element-ui+vue-treeselect下拉框的校驗(yàn)過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07