Core: by building a prototype interceptor, the array can first modify its own methods, including push, pop, shift, unshift, splice, sort, and reverse. By redefining the contents of the above methods, the trigger dependency is realized when calling the above methods, so as to inform the subscribers listening to the number of groups to execute the corresponding update function.
To minimize the implementation code:
const arrayPrtot = Array.prototype const arrayMethods = Object.create(arrayPrtot); const orig = arrayPrtot.push;//Cache raw method Object.defineProperty(arrayMethods, 'push', { value: function mutator(...args) { console.log('I used it. push Changed the array') return orig.apply(this, args) }, enumerable: false, writable: true, configurable: true }) var arr = []; arr.__proto__ = arrayMethods;//Add an interceptor to the array you want to listen to arr.push(1); console.log(arr);
The console output is as follows:
The following is the source code of vue implementation:
/* * not type checking this file because flow doesn't play well with * dynamically accessing methods on Array prototype */ import { def } from '../util/index' const arrayProto = Array.prototype export const arrayMethods = Object.create(arrayProto) const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] /** * Intercept mutating methods and emit events */ methodsToPatch.forEach(function (method) { // cache original method const original = arrayProto[method] def(arrayMethods, method, function mutator (...args) { const result = original.apply(this, args) const ob = this.__ob__ let inserted switch (method) { case 'push': case 'unshift': inserted = args break case 'splice': inserted = args.slice(2) break } if (inserted) ob.observeArray(inserted) // notify change ob.dep.notify() return result }) })