您好,登錄后才能下訂單哦!
之前梳理Vue數據響應思路 時沒有考慮數組的情況。
js 中數組有很多實例方法,其中有一部分會改變數組本身的值,比如 push pop shift unshift 等,這些方法被稱為變異方法,這些變異方法也是 Vue 開發中常用的數組操作方法。那么要實現對數組的觀測,首先要考慮的就是如何截獲這些變異方法的調用。
簡單來說,Vue 是通過保持這些數組變異方法原有功能不變的前提下,對其功能進行擴展來實現攔截的。具體怎么操作,可以先看一下例子:
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 函數,再重新定義 add10 函數,在重新定義的函數體里就可以執行額外增加的功能,比如上例中的 console.log('截獲了add10操作'),然后執行緩存的 add10 函數即 originalAdd10,并將結果返回,原理大抵如此。
那么,具體可實現如下:
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(`我截獲了對數組的${method}操作`) return result } }) const arr = ['kobe', 'jordan'] arr.__proto__ = arrayMethods arr.push('harden') // '我截獲了對數組的push操作' console.log(JSON.stringify(arr)) // '["kobe","jordan","harden"]'
以上,mutationMethods 是所有要攔截的數組變異方法的集合。
整體思路就是通過設置數組對象的 __proto__ 屬性的值為一個新對象 arrayMethods,以代理數組 mutationMethods 中的變異方法,并將 arrayMethods 的原型設置為數組構造函數本來的原型,這樣方能保證除卻代理的方法以外,不影響數組本身的其它方法和屬性。
其中:
const arrayMethods = Object.create(Array.prototype)
以上實現了 arrayMethods 的原型是數組構造函數本來的原型,即 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(`我截獲了對數組的${method}操作`) return result } })
將 mutationMethods 進行循環,在 arrayMethods 對象上以 mutationMethods 中各元素為 key,即方法名,定義作為攔截器的同名變異方法。
具體:
const result = arrayProto[method].apply(this, args)
執行緩存的 Array.prototype,即 arrayProto 中對應的變異方法,并傳入 this 以及 args,也就是將來調用該方法的數組對象,和調用該方法時傳入的參數(或參數列表)轉化成的參數數組,并將結果給到變量 result。
這里使用了解構賦值的方式將參數(或參數列表)轉化成了參數數組,這么做是因為不能確定參數的個數,所以只能使用 apply(不能用 call),并傳入參數數組。
之后:
console.log(`我截獲了對數組的${method}操作`)
也就是攔截之后要額外執行的操作了。
最后:
return result
將數組原變異方法執行的結果返回,保證原有功能不受影響。
forEach 執行完之后:
const arr = ['kobe', 'jordan'] arr.__proto__ = arrayMethods
聲明并初始化 arr,并將 arr 的 __proto__ 指向 arrayMethods,這樣便代理了 mutationMethods 中的變異方法。
最終:
arr.push('harden') // '我截獲了對數組的push操作' console.log(JSON.stringify(arr)) // '["kobe","jordan","harden"]'
數組對象手動擴展的功能以及原功能均正常,實現了數組變異方法的攔截。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。