核心:通过建立原型拦截器,首先数组能够修改自身的方法有push,pop,shift,unshift,splice,sort,resverse,通过重新定义上述方法中的内容,来实现调用上述方法时触发依赖,从而通知监听该数组的订阅者执行相应的更新函数。
一下为最小化的实现代码:
const arrayPrtot = Array.prototype
const arrayMethods = Object.create(arrayPrtot);
const orig = arrayPrtot.push;//缓存原始方法
Object.defineProperty(arrayMethods, 'push', {
value: function mutator(...args) {
console.log('我使用了push改变了数组哦')
return orig.apply(this, args)
},
enumerable: false,
writable: true,
configurable: true
})
var arr = [];
arr.__proto__ = arrayMethods;//给需要监听的数组加上拦截器
arr.push(1);
console.log(arr);
控制台输出如下:
以下为vue实现的源码:
/*
* 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
})
})
其具体实现原理如图所示: