Vue源码探究之状态初始化(6)
initWatcher 为传入的观察对象创建监视器,比较简单。值得注意的是参数的传入类型,观察对象 expOrFn 可以有两种方式,一种是字符串,一种是函数,在 Watcher 类中对此参数进行了检测,而在初始化的函数里不对它做任何处理。handler 对象也可以接受对象或字符串类型,在代码中对这两种传入方式做判断,最终找到handler引用的函数传入 $watch。
stateMixin
探索完了 initState 函数之后,继续来看看 state 混入的方法 stateMixin,在这个函数里会提供上面还未曾提到的 $watch 方法的具体实现:
// 定义并导出stateMixin函数,接收参数Vue
export function stateMixin (Vue: Class<Component>) {
// 使用 Object.defineProperty 方法直接声明定义对象时,flow会发生问题
// 所以必须在此程序化定义对象
// flow somehow has problems with directly declared definition object
// when using Object.defineProperty, so we have to procedurally build up
// the object here.
// 定义dataDef对象
const dataDef = {}
// 定义dataDef的get方法,返回Vue实例私有属性_data
dataDef.get = function () { return this._data }
// 定义propsDef对象
const propsDef = {}
// 定义propsDef的get方法,返回Vue实例私有属性_props
propsDef.get = function () { return this._props }
// 非生产环境下,定义dataDef和propsDef的set方法
if (process.env.NODE_ENV !== 'production') {
// dataDef的set方法接收Object类型的newData形参
dataDef.set = function (newData: Object) {
// 提示避免传入对象覆盖属性$data
// 推荐使用嵌套的数据属性代替
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
)
}
// 设置propsDef的set方法为只读
propsDef.set = function () {
warn(`$props is readonly.`, this)
}
}
// 定义Vue原型对象公共属性$data,并赋值为dataDef
Object.defineProperty(Vue.prototype, '$data', dataDef)
// 定义Vue原型对象公共属性$props,并赋值为propsDef
Object.defineProperty(Vue.prototype, '$props', propsDef)
// 定义Vue原型对象的$set方法,并赋值为从观察者导入的set函数
Vue.prototype.$set = set
// 定义Vue原型对象的$delete方法,并赋值为从观察者导入的del函数
Vue.prototype.$delete = del
// 定义Vue原型对象的$watch方法
// 接收字符串或函数类型的expOrFn,从命名中可看出希望为表达式或函数
// 接收任何类型的cb,这里希望为回调函数或者是一个对象
// 接收对象类型的options
// 要求返回函数类型
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Object
): Function {
// 把实例赋值给vm变量,类型需为Component
const vm: Component = this
// 如果cb是纯粹的对象类型
if (isPlainObject(cb)) {
// 返回createWatcher函数
return createWatcher(vm, expOrFn, cb, options)
}
// 定义观察目标的options,大多数情况下为undefined
options = options || {}
// 定义options的user属性值为true,标识为用户定义
options.user = true
// 创建watcher实例
const watcher = new Watcher(vm, expOrFn, cb, options)
// 如果options的immediate为真
if (options.immediate) {
// 在vm上调用cb回调函数,并传入watcher.value作为参数
cb.call(vm, watcher.value)
}
// 返回unwatchFn函数
return function unwatchFn () {
// 执行watcher.teardown()方法清除观察
watcher.teardown()
}
}
}
内容版权声明:除非注明,否则皆为本站原创文章。
