Vue 源码之数组更新检测

Vue 源码之数组更新检测

Vue 通用 Object.defineProperty 劫持数组,发布订阅模式添加订阅或者触发通知,从而实现双向绑定的。

本篇主要讲讲对于数组的变化, Vue 是如何检测的。

变异数组方法

Vue 创建了变异数组方法, 即保持数组方法原有功能不变的前提下对其进行功能拓展。

例子:

在原有函数输出的基础上,再输出 test

	function fn(a){ console.log(a) }
	var cache = fn;
	fn = function(a){
	    console.log('test')
		cache (a)
	}
	fn(123)		
	//输出:
	//test
	//123

数组更新检测

Vue 对 push()、pop()、shift()、unshift()、splice()、sort()、reverse() 等七个方法进行了功能拓展(变异数组)。

创建一个新对象继承原数组函数的方法,代理新对象的数组方法,返回和原数组一样的值,同时为数组列表注册订阅者对象,并发送通知更新响应属性

位置:./src/core/observer/array.js

源码:

const arrayProto = Array.prototype		// 储存数组原型方法
export const arrayMethods = Object.create(arrayProto)	// 创建一个新对象继承数组

;[ 'push',  'pop', 'shift', 'unshift',  'splice', 'sort', 'reverse' ]
.forEach(function (method) {
  const original = arrayProto[method]	// 缓存原数组方法
  /* 	
  *	def 函数:重新定义这个新数组对象
  *	arrayMethods[method] 的值为 mutator 的返回值 
  */
  def(arrayMethods, method, function mutator (...args) {
    const result = original.apply(this, args)		// 运行的结果仍为原数组方法运行结果,并返回这个值
    const ob = this.__ob__		// __ob__ 监听属性
    let inserted					// 处理数组方法的入参
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted)	// observeArray:观察数组项的列表(为每一项添加__ob__属性,即监听器) 
    ob.dep.notify()	  // 给订阅者发送消息,触发更新
    return result
  })
})

def 函数是通过 Object.defineProperty 重新定义了对象的值,貌似Vue 3.x 以后准备使用 Proxy 来进行这种代理行为

源码:

export function def (obj: Object, key: string, val: any, enumerable?: boolean) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  })
}

observeArray 就是简单的遍历一遍数组,然后给数组添加监听器

源码:

observeArray (items: Array) {
  for (let i = 0, l = items.length; i < l; i++) {
    observe(items[i])
  }
}

你可能感兴趣的:(Vue)