vue学习,简单手写实现数组的变化监测
vue的对象Object的监听是通过 js对象原型上的 Object.defineProerty()方法设置 setter 和 getter 来实现的,但是数组 Array没有 这个方法,所以方法有所不同,但是万变不离其宗,对于变化的监测原理还是相似的,就是在获取数据时收集依赖,在数据变化时通知依赖更新。首先思考一下我们在vue中使用 数组时的方法:
data(){
return{
arr:[1,2,3]
}
}
可以看出数组arr还是定义在了一个对象中,所以要用到这个数组的时候,必然会触发arr的getter,所以我们可以知道数组什么时候会读取,但是要知道数组什么时候发生变化,需要对操作的数组的方法拦截,经过整理我们知道js改变数组自身内容的方法有7个:push,pop,shift,unshift,splice,sort,reverse,我们拿push方法举例。
// 原生push方法
let arr = []
arr.push('111')
// vue 拦截数组原理
Array.prototype.newPush = function(val){
console.log('数组被修改了')
this.push(val)
}
arr.newPush('111')
接下来实现数组所有方法的拦截
const arrayProto = Array.prototype
// 创建一个对象作为拦截器
export const arrayMethods = Object.create(arrayProto)
// 改变数组自身内容的7个方法
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
const original = arrayProto[method] // 缓存原生方法
Object.defineProperty(arrayMethods, method, {
enumerable: false,
configurable: true,
writable: true,
value:function mutator(...args){
const result = original.apply(this, args)
return result
}
})
})
在上面的代码中,首先创建了继承自Array原型的空对象arrayMethods,接着在arrayMethods上使用object.defineProperty方法将那些可以改变数组自身的7个方法遍历逐个进行封装。最后,当我们使用push方法的时候,其实用的是arrayMethods.push,而arrayMethods.push就是封装的新函数mutator,也就是说,实标上执行的是函数mutator,而mutator函数内部执行了original函数,这个original函数就是Array.prototype上对应的原生方法