The principle of array monitoring in Vue -- array method interceptor

Keywords: Vue

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
  })
})

 

 

Posted by Thora_Fan on Sat, 23 Nov 2019 13:13:29 -0800