响应式入口
/** * 两件事: * 数据响应式的入口:分别处理 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)—— 响应式原理