今天,兄弟狗焕闷闷不乐的找到我。
面试官问他:new Vue()发生了什么,能给我说说吗?
狗焕拽进了拳头,憋了半天,敢怒不敢言。
我看穿了他的心事,写下这篇文档,希望我的兄弟狗焕可以如从前那样,快乐的在夕阳下奔跑,开心起来。
为了更好的让狗焕理解整个过程,上一篇我们讲的重读vue源码(1)—— 调试环境搭建,为何狗焕心事重重可以派上用场了,我们通过打断点的方式一步一步的向前看,代码怎么走下去的。
现在进入正题,发车了。
以下是本文目录:
- 从打断点开始观察实例化经历了哪些过程
- 第一步:进入`src/core/instance/index.ts`文件
- 第二步:进入`src/core/instance/init.ts`文件
- 第三步:进入`src/core/instance/lifecycle.ts`,查看`initLifecycle`执行代码
- 第四步:进入`src/core/instance/events.ts`,查看`initEvents`执行代码
- 第五步:进入`src/core/instance/render.ts`,查看`initRender`执行代码
- 第六步:进入`src/core/instance/lifecycle.ts`,查看`callHook`执行代码
- 第七步:进入`src/core/instance/inject.ts`,查看`initInjections`执行代码
- 第八步:进入`src/core/instance/state.ts`,查看`initState`执行代码
- 第九步:进入`src/core/instance/inject.ts`,查看`initProvide`执行代码
- 对断点结果总结一下
- 手写new Vue(),不再让你手足无措
- 手写代码地址
- 写到后面
从打断点开始观察实例化经历了哪些过程
从上一篇重读vue源码(1)—— 调试环境搭建,为何狗焕心事重重的01test.html这个文件作为例子讲解。
在实例化的这里打断点,往下看它会执行哪些步骤。
第一步:进入src/core/instance/index.ts文件
实例化进入到上述文件中,执行了_init的原型方法。
“好,继续看这个this._init()方法执行了什么鬼。”狗焕激动的跟我说着。
第二步:进入src/core/instance/init.ts文件
前面主要是一些变量的定义、边界条件的判断。最核心的是下面这部分的代码。
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate', undefined, false /* setContext */)
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
狗焕说:“我大概知道执行一些什么事情了”。让我们进一步看这部分核心代码执行了一些什么方法吧。
好的,那我把上面的这几个参数一步步的打断点向下执行吧。
第三步:进入src/core/instance/lifecycle.ts,查看initLifecycle执行代码
对vm.$parent、vm.$root、vm._watcher等变量进行赋值和初始化的操作。
第四步:进入src/core/instance/events.ts,查看initEvents执行代码
初始化vm._events,然后通过updateComponentListeners将vm和配置中传入的_parentListeners作为入参,去执行一个什么监听,大概知道这样一个逻辑,没有看的太深。
第五步:进入src/core/instance/render.ts,查看initRender执行代码
将createElement挂载到vm上,并且对vm.$attrs和vm.$listeners设置成响应式的数据。
第六步:进入src/core/instance/lifecycle.ts,查看callHook执行代码
执行生命周期钩子函数,循环遍历传进来的生命周期函数(所以这里存储生命周期函数应该是一个数组)。
第七步:进入src/core/instance/inject.ts,查看initInjections执行代码
对inject接收到的数据设置成响应式。
第八步:进入src/core/instance/state.ts,查看initState执行代码
首先兼容了Vue@3的Composition API,集成了initSetup方法。然后对props、methods、data、computed、watch等进行初始化。
第九步:进入src/core/instance/inject.ts,查看initProvide执行代码
对传入的provide参数到的数据设置成响应式。
对断点结果总结一下
// 对`vm.$parent、vm.$root、vm._watcher`等变量进行赋值和初始化的操作
initLifecycle(vm)
// 初始化vm._events,通过updateComponentListeners将vm和_parentListeners执行监听方法
initEvents(vm)
// 将createElement挂载到vm上,并且对`vm.$attrs`和`vm.$listeners`设置成响应式的数据
initRender(vm)
// 执行beforeCreate生命周期钩子函数
callHook(vm, 'beforeCreate', undefined, false)
// 对inject接收到的数据设置成响应式
initInjections(vm)
// 对props、methods、data、computed、watch等数据进行初始化。
initState(vm)
// 对传入的provide参数到的数据设置成响应式
initProvide(vm)
// 执行created生命周期钩子函数
callHook(vm, 'created')
手写new Vue(),不再让你手足无措
方便狗焕记得更深刻,我把上面这部分的学习写成一段手写代码,让他学习更轻松。
html模块:
js模块:
执行一下,看看会发生什么。
跟预期一样,很棒棒。
手写代码地址
为了帮助友友们更好的理解和学习vue源码知识,我把手写代码放在点击这里。打开链接,就可以看到我手写的这段代码了。后续的一些源码重读部分的手写代码,也会放在一起。
防止一会找不到丢失了,友友们可以star或者fork这个手写项目,以后打开自己的码云主页就能看到啦,学习更高效更方便。
写在最后
看完这篇文档,果然兄弟狗焕开心的回到电脑前开始学习,原来学习真的可以很轻松。
如果这篇文档对你有帮助,欢迎点赞、关注或者在评论区留言,我会第一时间对你的认可进行回应。精彩内容在后面,防止跑丢,友友们可以先关注我,每一篇文章都能及时通知不会遗失。