在上一篇文章《浅析Vue源码(一)-- 造物创世》中提到在定义了一个 Vue Class的时候会引入initMixin 来初始化一些功能,这篇文章就来讲讲initMixin到底初始化了哪些原理呢?

initMixin来源init.js

let uid = 0export function initMixin (Vue: Class<Component>) {Vue.prototype._init = function (options?: Object) {const vm: Component = this// a uidvm._uid = uid++let startTag, endTag/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {startTag = `vue-perf-start:${vm._uid}`endTag = `vue-perf-end:${vm._uid}`mark(startTag)}// 如果是Vue的实例,则不需要被observe// a flag to avoid this being observedvm._isVue = true// merge options// 第一步: options参数的处理if (options && options._isComponent) {// optimize internal component instantiation// since dynamic options merging is pretty slow, and none of the// internal component options needs special treatment.initInternalComponent(vm, options)} else {// mergeOptions接下来我们会详细讲哦~vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}// 第二步: renderProxy/* istanbul ignore else */if (process.env.NODE_ENV !== 'production') {initProxy(vm)} else {vm._renderProxy = vm}// expose real selfvm._self = vm// 第三步: vm的生命周期相关变量初始化initLifecycle(vm)// 第四步: vm的事件监听初始化initEvents(vm)// 第五步: vm的编译render初始化initRender(vm)// 第六步: vm的beforeCreate生命钩子的回调callHook(vm, 'beforeCreate')// 第七步: vm在data/props初始化之前要进行绑定initInjections(vm) // resolve injections before data/props// 第八步: vm的sate状态初始化initState(vm)// 第九步: vm在data/props之后要进行提供initProvide(vm) // resolve provide after data/props// 第十步: vm的created生命钩子的回调callHook(vm, 'created')/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {vm._name = formatComponentName(vm, false)mark(endTag)measure(`vue ${vm._name} init`, startTag, endTag)}// 第十一步:render & mountif (vm.$options.el) {vm.$mount(vm.$options.el)}}
}
复制代码

从上面一点一点注释可以看出,主要是为我们的Vue原型上定义一个方法_init。然后当我们执行new Vue(options) 的时候,会调用这个方法。而这个_init方法的实现,便是我们需要关注的地方。 前面定义vm实例都挺好理解的,主要我们来看一下mergeOptions这个方法,其实Vue在实例化的过程中,会在代码运行后增加很多新的东西进去。我们把我们传入的这个对象叫options,实例中我们可以通过vm.$options访问到。

mergeOptions

mergeOptions主要分成两块,就是resolveConstructorOptions(vm.constructor)和options,mergeOptions这个函数的功能就是要把这两个合在一起。options是我们通过new Vue(options)实例化传入的,所以,我们主要需要研究的是resolveConstructorOptions这个函数的功能。

resolveConstructorOptions 处理 options

export function resolveConstructorOptions (Ctor: Class<Component>) {let options = Ctor.options// 首先需要判断该类是否是Vue的子类if (Ctor.super) {const superOptions = resolveConstructorOptions(Ctor.super)const cachedSuperOptions = Ctor.superOptions// 来判断父类中的options 有没有发生变化if (superOptions !== cachedSuperOptions) {// super option changed,// need to resolve new options.Ctor.superOptions = superOptions// check if there are any late-modified/attached options (#4976)const modifiedOptions = resolveModifiedOptions(Ctor)// update base extend optionsif (modifiedOptions) {// 当为Vue混入一些options时,superOptions会发生变化,此时于之前子类中存储的cachedSuperOptions已经不相等,所以下面的操作主要就是更新sub.superOptionsextend(Ctor.extendOptions, modifiedOptions)}options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)if (options.name) {options.components[options.name] = Ctor}}}return options
}
复制代码

在这里我们大概会产生一个疑惑,可能不太清楚Ctor类里面每个属性到底代表了什么? 下面我们来看这一段代码:

 Sub.options = mergeOptions(Super.options,extendOptions)Sub['super'] = SuperSub.superOptions = Super.optionsSub.extendOptions = extendOptionsSub.sealedOptions = extend({}, Sub.options)
复制代码

继承自Super 的子类Sub。换句话说,Ctor其实是继承了Vue,是Vue的子类。 那又有一个疑惑了,mergeOptions是什么呢?

export function mergeOptions (parent: Object,child: Object,vm?: Component
): Object {//...// 统一props格式normalizeProps(child)// 统一directives的格式normalizeDirectives(child)// 如果存在child.extends// ...// 如果存在child.mixins// ...// 针对不同的键值,采用不同的merge策略const options = {}let keyfor (key in parent) {mergeField(key)}for (key in child) {if (!hasOwn(parent, key)) {mergeField(key)}}function mergeField (key) {const strat = strats[key] || defaultStratoptions[key] = strat(parent[key], child[key], vm, key)}return options
}
复制代码

上面采取了对不同的field采取不同的策略,Vue提供了一个strats对象,其本身就是一个hook,如果strats有提供特殊的逻辑,就走strats,否则走默认merge逻辑。

const strats = config.optionMergeStrategies
strats.el  = strats.propsData = ...
strats.data = ...
strats.watch  ...
....const defaultStrat = function (parentVal: any, childVal: any): any {return childVal === undefined? parentVal: childVal
}
复制代码

看到这里,我们终于把业务逻辑以及组件的一些特性全都放到了vm.options拿到可用的信息。框架基本上都是对输入宽松,对输出严格,vue也是如此,不管使用者添加了什么代码,最后都规范的收入vm.$options中。

renderProxy

这一步比较简单,主要是定义了vm._renderProxy,这是后期为render做准备的,作用是在render中将this指向vm._renderProxy。一般而言,vm._renderProxy是等于vm的,但在开发环境,Vue动用了Proxy这个新API,有关Proxy,大家可以读读深入浅出ES6(十二):代理 Proxies, 这里不再展开。

github喜欢的话可以给我一个star哦~ 接下来会涉及到以下解析哦

initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm)
initState(vm)
initProvide(vm)
callHook(vm, 'created')
复制代码

浅析Vue源码(二)—— initMixin(上)相关推荐

  1. 深入剖析Vue源码 - 响应式系统构建(上)

    从这一小节开始,正式进入Vue源码的核心,也是难点之一,响应式系统的构建.这一节将作为分析响应式构建过程源码的入门,主要分为两大块,第一块是针对响应式数据props,methods,data,comp ...

  2. diff算法_深入剖析Vue源码 - 来,跟我一起实现diff算法!__Vue.js

    这一节,依然是深入剖析Vue源码系列,上几节内容介绍了Virtual DOM是Vue在渲染机制上做的优化,而渲染的核心在于数据变化时,如何高效的更新节点,这就是diff算法.由于源码中关于diff算法 ...

  3. 源码解读_入口开始解读Vue源码系列(二)——new Vue 的故事

    作者:muwoo 转发链接:https://github.com/muwoo/blogs/blob/master/src/Vue/2.md 目录 入口开始解读Vue源码系列(一)--造物创世 入口开始 ...

  4. vue实例没有挂载到html上,vue 源码学习 - 实例挂载

    前言 在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法. src ├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能. ├── ...

  5. 【vuejs深入三】vue源码解析之二 htmlParse解析器的实现

    写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. 昨天博主分析了一下在vue中,最为基础核心的api,parse函数,它的作用是将vue的模板字符串转换成ast,从而 ...

  6. vue源码分析系列二:$mount()和new Watcher()的执行过程

    续vue源码分析系列一:new Vue的初始化过程 在initMixin()里面调用了$mount() if (vm.$options.el) {vm.$mount(vm.$options.el);/ ...

  7. Vue源码之mustache模板引擎(二) 手写实现mustache

    Vue源码之mustache模板引擎(二) 手写实现mustache mustache.js 个人练习结果仓库(持续更新):Vue源码解析 webpack配置 可以参考之前的笔记Webpack笔记 安 ...

  8. vue 二维数组_最近研究Vue源码时我发现的一些好玩函数

    来源 | segmentfault.com/u/chinamasters 作者 | chinamasters 最近在深入研究vue源码,把学习过程中,看到的一些好玩的的函数方法收集起来做分享,希望对大 ...

  9. vue 初始化方法_前端发展方向指南—Vue源码初始化

    Vue 的源码结构比较绕,同时使用了大量的面向对象的高级技巧.重写方法,扩展方法,多态等应用.从 Vue 实例的加载过程就可以看出来,这一节重点看看 Vue 的源码加载流程是什么. 前言 vue已是目 ...

  10. vue源码学习--vue源码学习入门

    本文为开始学习vue源码的思路整理.在拿到vue项目源码的之后看到那些项目中的文件夹,会很困惑,不知道每个文件夹内的世界,怎么变换,怎样的魔力,最后产生了vue框架.学习源码也无从学起.我解决了这些困 ...

最新文章

  1. EOS从入门到精通-账户体系(文字稿)
  2. 查看Centos7系统参数和机器参数
  3. Snowleopard 截屏
  4. “约见”面试官系列之常见面试题之第九十四篇之MVVM框架(建议收藏)
  5. OpenGL ES入门
  6. asp.net AJAX 使用webServices调用时,出现“WebService”未定义
  7. asp.net:验证控件中ValidationExpression的写法
  8. 在树莓派上进行python编程_在树莓派上用Python控制LED
  9. 3D动态视频屏保热带鱼水族馆
  10. LaTeX 中的花体字母
  11. ai建立使用图案_AI如何建立剪切蒙版
  12. mysql存储过程转义字符_mysql存储过程转义字符
  13. [PTA]6-12 判断奇偶性
  14. 速看四川省企业技术中心拟认定名单已发布,共181家
  15. CRAFT字符检测算法和SynthText合成文本数据集
  16. php省市区中文截取
  17. 电信各种视频免流卡申请地址合集附地址失效解决方法
  18. 谷歌提出Flan-T5,一个模型解决所有NLP任务
  19. 2022最新简约好用的夏雨图床系统源码+UI超好看
  20. 邓俊辉数据结构学习笔记2

热门文章

  1. Sublime 3 打开GBK 编码文件中文乱码 解决办法
  2. 算法:Valid Sudoku(有效的数独)
  3. 可访问性之于类和对象
  4. python服务端开发调试日志系统_Loglog首页、文档和下载 - 基于 Python2.7 的日志系统 - OSCHINA - 中文开源技术交流社区...
  5. matplot画图控制marker点的个数_专刊主编述评 中药质量标志物(Qmarker):提高中药质量标准及质量控制理论和促进中药产业科学发展...
  6. Python模拟新浪微博登录转载,是我的那篇资料来源
  7. Hadoop中的一些基本操作
  8. centos 中如何将python更新到最新的版本
  9. 牛客 动物森友会(最大流+二分)
  10. 快速突破面试算法之排序篇