响应式入口
/**
* 两件事:
* 数据响应式的入口:分别处理 props、methods、data、computed、watch
* 优先级:props、methods、data、computed 对象中的属性不能出现重复,优先级和列出顺序一致
* 其中 computed 中的 key 不能和 props、data 中的 key 重复,methods 不影响
*/
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
// 处理 props 对象,为 props 对象的每个属性设置响应式,并将其代理到 vm 实例上
if (opts.props) initProps(vm, opts.props)
// 处理 methos 对象,校验每个属性的值是否为函数、和 props 属性比对进行判重处理,最后得到 vm[key] = methods[key]
if (opts.methods) initMethods(vm, opts.methods)
/**
* 做了三件事
* 1、判重处理,data 对象上的属性不能和 props、methods 对象上的属性相同
* 2、代理 data 对象上的属性到 vm 实例
* 3、为 data 对象的上数据设置响应式
*/
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
/**
* 三件事:
* 1、为 computed[key] 创建 watcher 实例,默认是懒执行
* 2、代理 computed[key] 到 vm 实例
* 3、判重,computed 中的 key 不能和 data、props 中的属性重复
*/
if (opts.computed) initComputed(vm, opts.computed)
/**
* 三件事:
* 1、处理 watch 对象
* 2、为 每个 watch.key 创建 watcher 实例,key 和 watcher 实例可能是 一对多 的关系
* 3、如果设置了 immediate,则立即执行 回调函数
*/
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
/**
* 其实到这里也能看出,computed 和 watch 在本质是没有区别的,都是通过 watcher 去实现的响应式
* 非要说有区别,那也只是在使用方式上的区别,简单来说:
* 1、watch:适用于当数据变化时执行异步或者开销较大的操作时使用,即需要长时间等待的操作可以放在 watch 中
* 2、computed:其中可以使用异步方法,但是没有任何意义。所以 computed 更适合做一些同步计算
*/
}
参考资料
- Vue 源码解读(3)—— 响应式原理