为什么Vue3.0使用Proxy实现数据监听(defineProperty表示不背这个锅)

2020-06-12 20:45:47易采站长站整理


/*
* not type checking this file because flow doesn't play well with
* dynamically accessing methods on Array prototype
*/

import { def } from '../util/index'

// 复制数组构造函数的原型,Array.prototype也是一个数组。
const arrayProto = Array.prototype
// 创建对象,对象的__proto__指向arrayProto,所以arrayMethods的__proto__包含数组的所有方法。
export const arrayMethods = Object.create(arrayProto)

// 下面的数组是要进行重写的方法
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]

/**
* Intercept mutating methods and emit events
*/
// 遍历methodsToPatch数组,对其中的方法进行重写
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method] // def方法定义在lang.js文件中,是通过object.defineProperty对属性进行重新定义。
// 即在arrayMethods中找到我们要重写的方法,对其进行重新定义
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
// 上面已经分析过,对于push,unshift会新增索引,所以需要手动observe
case 'push':
case 'unshift':
inserted = args
break
// splice方法,如果传入了第三个参数,也会有新增索引,所以也需要手动observe
case 'splice':
inserted = args.slice(2)
break
}
// push,unshift,splice三个方法触发后,在这里手动observe,其他方法的变更会在当前的索引上进行更新,所以不需要再执行ob.observeArray
if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()
return result
})
})

三 Object.defineProperty VS Proxy

上面已经知道

Object.defineProperty
对数组和对象的表现是一致的,那么它和
Proxy
对比存在哪些优缺点呢?

1. Object.defineProperty只能劫持对象的属性,而Proxy是直接代理对象。

由于

Object.defineProperty
只能对属性进行劫持,需要遍历对象的每个属性,如果属性值也是对象,则需要深度遍历。而
Proxy
直接代理对象,不需要遍历操作。

2. Object.defineProperty对新增属性需要手动进行Observe。

由于

Object.defineProperty
劫持的是对象的属性,所以新增属性时,需要重新遍历对象,对其新增属性再使用
Object.defineProperty