vue對數組的observe做了哪些處理?
Vue的Observer對數組做了單獨的處理,對數組的方法進行編譯,並賦值給數組屬性的proto屬性上,因為原型鏈的機制,找到對應的方法就不會繼續往上找了。編譯方法中會對一些會增加索引的方法(push,unshift,splice)進行手動observe。
vue的Observer類定義在core/observer/index.js 中
export class Observer {
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
this.walk(value)
}
可以看到,vue的Observer對數組做了單獨的處理。
// can we use __proto__?
export const hasProto = '__proto__' in {}
hasProto
是判斷數組的實例是否有__proto__
屬性,如果有proto 屬性就會執行protoAugment 方法,將arrayMethods 重寫到原型上。
src\core\observer\index.js
/**
* Augment a target Object or Array by intercepting
* the prototype chain using __proto__
*/
function protoAugment (target, src: Object) {
/* eslint-disable no-proto */
target.__proto__ = src
/* eslint-enable no-proto */
}
arrayMethods 是對數組的方法進行重寫,定義在core/observer/array.js 中
// 复制数组构造函数的原型,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
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()
return result
})
})
/**
* Define a property.
*/
export function def (obj: Object, key: string, val: any, enumerable?: boolean) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
})
}
references:
【深入vue】為什麼Vue3.0不再使用defineProperty實現數據監聽?
Top comments (0)