- 借用原生方法,重写常用api,并在调用时,对新增加的元素进行响应式处理
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
methodsToPatch.forEach(function (method) {
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
...
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
...
return result
})
})
- 定义响应式数据时,对数组类型、对象类型分别处理(目前v-for支持set、map数据类型,但它们自身不是响应式)
export class Observer {
value: any;
dep: Dep;
vmCount: number;
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
this.walk(value)
}
}
...
- 如果如果浏览器支持__proto__,直接将数组实例原型修改为arrayMethods
function protoAugment (target, src: Object) {
target.__proto__ = src
}
- 如果不支持__proto__,进行遍历,遍历arrayMethods的自用属性,使用改造后的方法替换数组实例上原有方法
function copyAugment (target: Object, src: Object, keys: Array<string>) {
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i]
def(target, key, src[key])
}
}