Vue2.x源码:new Vue()做了啥
- 例子1
- new Vue做了啥?
- new Vue做了啥,源码解析
- initMixin函数 初始化 – 初始化Vue实例的配置
- initLifecycle函数 – 初始化生命周期钩子函数
- initEvents – 初始化事件系统
- 初始化渲染 initRender
- 初始化inject选项
例子1
<div id="app"><div class="home"><h1>{{title}}</h1></div>
</div>
new Vue({el: '#app',data: () => {return {title: 'Home Page'}}
})

更多详细内容,请微信搜索“前端爱好者“, 戳我 查看 。
new Vue()做了啥?
在Vue.js 2.x的源码中,new Vue()的主要作用是创建一个Vue实例。当我们调用new Vue()时,会经过以下几个步骤:
- 初始化Vue实例的配置:Vue会将我们传入的配置对象进行初始化,包括数据、计算属性、方法等。
- 初始化生命周期钩子函数:Vue会在初始化过程中执行一系列的生命周期钩子函数,例如
beforeCreate、created、beforeMount、mounted等。 - 初始化事件系统:Vue会为实例创建一个事件总线,用于处理事件的监听和触发。
- 解析模板:如果配置中指定了
template选项,Vue会将模板解析成渲染函数,以便后续的渲染过程中使用。 - 初始化渲染:Vue会创建一个虚拟DOM,并将之前解析的渲染函数进行渲染,生成真实DOM,并将其挂载到页面上。
- 数据响应式处理:Vue会对实例中的数据进行响应式处理,即通过劫持数据的访问和修改,实现数据的双向绑定。
在这个过程中,Vue还会做很多其他的工作,例如处理指令、组件注册、依赖收集等,以确保整个应用的正常运行和响应式更新。
以上只是对new Vue()的简单概述,具体的实现细节涉及到很多源码内容,在Vue.js的源码中可以详细了解其中的实现原理。
new Vue()做了啥,源码解析
vue源码版本vue2.5.2
new Vue()会执行_init方法,而_init方法在initMixin函数中定义。
src/core/instance/index.js文件中定义了Vue
function Vue (options) {this._init(options)
}initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)export default Vue
initMixin函数 初始化 – 初始化Vue实例的配置
- const vm: Component = this;定义vm等于Vue;
- vm._uid = uid++; vm存在_uid,自增
- vm._isVue = true;只有是经过vue实例化的。vm都存在_isVue属性为true值
- options && options._isComponent 当options存在_isComponent属性时,执行initInternalComponent(vm, options)
- 当组件options._isComponen不存在时,执行 mergeOptions( resolveConstructorOptions(vm.constructor), options || {},vm )
- m._renderProxy = vm;给vm定义一个_renderProxy 属性等于自身
- vm._self = vm;给vm定义一个_self 属性等于自身
- initLifecycle(vm);初始化生命周期相关实例属性
- initEvents(vm);初始化事件
- initRender(vm);定义$createElement() createElement的执行过程
- callHook(vm, ‘beforeCreate’);执行beforeCreate生命周期钩子
- initInjections(vm);
- initState(vm);将data代理至Vue._data data的代理
- initProvide(vm);初始化provide
- callHook(vm, ‘created’);执行created生命周期钩子
- vm. m o u n t ( v m . mount(vm. mount(vm.options.el)执行挂载
定义的 Vue.prototype._init
export function initMixin (Vue: Class<Component>) {Vue.prototype._init = function (options?: Object) {const vm: Component = this// a uid,自增IDvm._uid = uid++vm._isVue = true// merge options 合并optionsif (options && options._isComponent) {initInternalComponent(vm, options)} else {vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}vm._renderProxy = vm// expose real selfvm._self = vm// 初始化生命周期相关实例属性initLifecycle(vm)//初始化事件initEvents(vm)//定义$createElement() createElement的执行过程initRender(vm)// 执行beforeCreate生命周期钩子callHook(vm, 'beforeCreate')initInjections(vm) // resolve injections before data/props//将data代理至Vue._data data的代理initState(vm)// 初始化provideinitProvide(vm) // resolve provide after data/props// 执行created生命周期钩子callHook(vm, 'created')// 当options中存在el属性,则执行挂载if (vm.$options.el) {//挂载#app $mount执行过程vm.$mount(vm.$options.el)}}
}
initLifecycle函数 – 初始化生命周期钩子函数
initLifecycle 初始化生命周期相关变量即在vue实例上挂载一些属性并设置默认值,如
- p a r e n t , parent, parent,root,
- $children,
- $ref,vm._watcher,
- vm.__inactive,
- vm._directInactive,
- vm._isMounted,
- vm._isDestroyed,
- vm._isBeingDestroyed
export function initLifecycle (vm: Component) {const options = vm.$options// locate first non-abstract parentlet parent = options.parent//当前组件存在父级并且当前组件不是抽象组件if (parent && !options.abstract) {//通过while循环来向上循环,如果当前组件的父级是抽象组件并且也存在父级,那就继续向上查找当前组件父级的父级while (parent.$options.abstract && parent.$parent) {//更新parentparent = parent.$parent}//把该实例自身添加进找到的父级的$children属性中parent.$children.push(vm)}//直到找到第一个不是抽象类型的父级时,将其赋值vm.$parentvm.$parent = parent//设置实例根元素。判断如果当前实例存在父级,那么当前实例的根实例$root属性就是其父级的根实例$root属性,如果不存在,那么根实例$root属性就是它自己vm.$root = parent ? parent.$root : vmvm.$children = []vm.$refs = {}vm._watcher = nullvm._inactive = nullvm._directInactive = false//实例是否已挂载vm._isMounted = false//实例是否已销毁vm._isDestroyed = false//实例是否正准备销毁vm._isBeingDestroyed = false
}
合并options之后

initEvents – 初始化事件系统
initEvents 初始化事件。 初始化的是父组件在模板中使用v-on或@注册的监听子组件内触发的事件。
export function initEvents (vm: Component) {
//在vm上新增_events属性并将其赋值为空对象,用来存储事件。vm._events = Object.create(null)vm._hasHookEvent = false// init parent attached events//获取父组件注册的事件赋给listeners,const listeners = vm.$options._parentListeners//如果listeners不为空,则调用updateComponentListeners函数,将父组件向子组件注册的事件注册到子组件的实例中if (listeners) {updateComponentListeners(vm, listeners)}
}
初始化渲染 initRender
initRender函数 初始化渲染.。
export function initRender (vm: Component) {vm._vnode = null // the root of the child treevm._staticTrees = null // v-once cached treesconst options = vm.$optionsconst parentVnode = vm.$vnode = options._parentVnode // the placeholder node in parent treeconst renderContext = parentVnode && parentVnode.context//实例上插槽vm.$slots = resolveSlots(options._renderChildren, renderContext)vm.$scopedSlots = emptyObject//在实例上定义_c函数和$_createElement函数vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)const parentData = parentVnode && parentVnode.datadefineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)}
初始化inject选项
inject 选项中的每一个数据key都是由其上游父级组件提供的,所以我们应该把每一个数据key从当前组件起,不断的向上游父级组件中查找该数据key对应的值,直到找到为止。
如果在上游所有父级组件中没找到,那么就看在inject 选项是否为该数据key设置了默认值,如果设置了就使用默认值,如果没有设置,则抛出异常。
export function initInjections (vm: Component) {
//调用resolveInject把inject选项中的数据转化成键值对的形式赋给resultconst result = resolveInject(vm.$options.inject, vm)if (result) {toggleObserving(false)//遍历result中的每一对键值Object.keys(result).forEach(key => {//调用defineReactive函数将其添加当前实例上defineReactive(vm, key, result[key])})toggleObserving(true)}
}
注意,在把result中的键值添加到当前实例上之前,会先调用toggleObserving(false),而这个函数内部是把shouldObserve = false,这是为了告诉defineReactive函数仅仅是把键值添加到当前实例上而不需要将其转换成响应式
resolveInject函数内部是如何把inject 选项中数据转换成键值对的。
export function resolveInject (inject: any, vm: Component): ?Object {if (inject) {// inject is :any because flow is not smart enough to figure out cached//创建一个空对象result,用来存储inject 选项中的数据key及其对应的值,作为最后的返回结果。const result = Object.create(null)const keys = hasSymbol? Reflect.ownKeys(inject).filter(key => {/* istanbul ignore next */return Object.getOwnPropertyDescriptor(inject, key).enumerable}): Object.keys(inject)for (let i = 0; i < keys.length; i++) {const key = keys[i]//provideKey就是上游父级组件提供的源属性const provideKey = inject[key].fromlet source = vm//while循环,从当前组件起,不断的向上游父级组件的_provided属性中(父级组件使用provide选项注入数据时会将注入的数据存入自己的实例的_provided属性中)查找,直到查找到源属性的对应的值,将其存入result中while (source) {if (source._provided && hasOwn(source._provided, provideKey)) {result[key] = source._provided[provideKey]break}source = source.$parent}if (!source) {//是否有default属性,如果有的话,则拿到这个默认值,官方文档示例中说了,默认值可以为一个工厂函数,所以当默认值是函数的时候,就去该函数的返回值,否则就取默认值本身。如果没有设置默认值,则抛出异常。if ('default' in inject[key]) {const provideDefault = inject[key].defaultresult[key] = typeof provideDefault === 'function'? provideDefault.call(vm): provideDefault} else if (process.env.NODE_ENV !== 'production') {warn(`Injection "${key}" not found`, vm)}}}return result}
}
官方文档中说inject 选项可以是一个字符串数组,也可以是一个对象,在上面的代码中只看见了处理当为对象的情况,那如果是字符串数组呢?怎么没有处理呢?
其实在初始化阶段_init函数在合并属性的时候还调用了一个将inject 选项数据规范化的函数normalizeInject
参考文档:
https://blog.csdn.net/weixin_40119412/article/details/128880336
相关文章:
Vue2.x源码:new Vue()做了啥
例子1new Vue做了啥?new Vue做了啥,源码解析 initMixin函数 初始化 – 初始化Vue实例的配置initLifecycle函数 – 初始化生命周期钩子函数initEvents – 初始化事件系统初始化渲染 initRender初始化inject选项 例子1 <div id"app"><div class"home&…...
iOS 借助DSYMTools工具定位到闪退的具体行数和方法名
1、下载 dSYMTools-master 工具,下载安装后,如下图: 2、通过Bugly或友盟等异常记录工具,找到闪退的内存地址和偏移量信息上图是Bugy记录的闪退信息,友盟的参考如下: 关于工具的原理和其他描述,…...
分布式解决方案与实战
分布式多线程性能调优 使用多线程优化接口 //下单业务public Object order( long userId){long start System.currentTimeMillis();//方法的开始时间戳(ms)JSONObject orderInfo remoteService.createOrder(userId);Callable<JSONObject> calla…...
GitHub入门介绍
GitHub是一个基于web的版本控制系统,主要用于代码管理和协作开发。它是开源的,并且提供了一系列的功能,方便开发人员进行版本控制、代码托管和团队协作。 以下是GitHub的一些基本概念和功能: 版本控制:GitHub使用Git作…...
IP与子网掩码之间的关系
子网掩码用于确认IP所在的网段,网络位与子网掩码相匹配 如果有另一台主机想要与这个IP地址进行通信,这时需要看两台主机的IP地址是否处于同一网段,处于同一网段才能相互ping通。 那么怎么判断是否处于同一网段呢?我们就看子网掩…...
文档或书籍扫描为 PDF:ScanPapyrus Crack
ScanPapyrus 可让您快速轻松地将文档或书籍扫描为 PDF,批处理模式使扫描过程快速高效,自动处理书籍并将其拆分为单独的页面 用于快速扫描文档、书籍或打印照片的扫描仪软件 快速扫描文档 使用此扫描仪软件,您无需在扫描仪和计算机之间来回移动…...
Clickhouse RoaringBitmap
https://blog.csdn.net/penriver/article/details/119736050 https://juejin.cn/post/7179956435806076988 BitMap适合连续密集的正整数存储,对于稀疏的正整数存储,其性能在很多时候是没办法和int数组相比的,尤其是正整数跨度较大的场景&…...
C语言第四十九弹----模拟使用strcpy函数
使用C语言模拟使用strcpy函数 定义:strcpy 函数是 C 标准库中用于字符串复制的函数。它接受两个参数,第一个参数 dest 是目标字符串的指针,第二个参数 src 是源字符串的指针,函数的功能是将源字符串复制到目标字符串中࿰…...
docker搭建maven私库Nexus3
什么是Maven私服? Maven 私服是一种特殊的Maven远程仓库,它是架设在局域网内的仓库服务,用来代理位于外部的远程仓库(中央仓库、其他远程公共仓库)。 当然也并不是说私服只能建立在局域网,也有很多公司会…...
Java 基础学习(十)包装类、异常
1 包装类 1.1 包装类概述 1.1.1 什么是包装类 在进行类型转换时,有一种特殊的转换:将 int 这样的基本数据类型转换为对象,如下图所示: 所有基本类型都有一个与之对应的类,即包装类(wrapper)。…...
STM32的基本定时器注意点
本文介绍了STM32基本定时器3个重要的寄存器PSC、ARR、CNT,以及缓冲机制和计数细节。 基本定时器的框图 预分频器寄存器(TIMx_PSC)可以在运行过程中修改它的数值,新的预分频数值将在下一个更新事件时起作用。因为更新事件发生时,会把 TIMx_PS…...
浅谈NLP和大模型的关系
目录 一、什么是NLP 二、NLP的应用举例 三、NLP的Python实现举例 四、NLP和大模型的关系 五、NLP的难点 5.1 内容的有效界定 5.2 消歧和模糊性 5.3 有瑕疵的或不规范的输入 5.4 语言行为与计划 六、研究热点 一、什么是NLP 如果单独说NLP这3个字母,具有两…...
k8s上安装KubeSphere
🍩安装KubeSphere 🍪前置环境🍪安装nfs-server文件系统🍪配置nfs-client🍪配置默认存储🍪创建了一个存储类🍪metrics-server集群指标监控组件 🍪安装KubeSphere🍪执行安装…...
Linux 链接器如何使用静态库来解析引用
文章目录 通过进行代码实践静态库在编译时被链接到可执行文件中的基本原理原理总结 QA:.obj文件是什么? 通过进行代码实践 链接器在解析引用时,可以使用静态库来满足对未定义符号的引用。以下是使用静态库的一般步骤: 编写代码: 首先&#…...
vue实现滑动验证
效果图: 源码地址:github文档地址: https://github.com/monoplasty/vue-monoplasty-slide-verify 使用步骤:1,安装插件: npm install --save vue-monoplasty-slide-verify 在main.js中使用一下ÿ…...
***Cpolar配置外网访问和Dashy
Dashy是一个开源的自托管的导航页配置服务,具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。你可以将自己常用的一些网站聚合起来放在一起,形成自己的导航页。一款功能超强大,颜值爆表的可定制专属导航页工具 结合cpolar内网工具,我们实现无需部署到公网服务器…...
Rancher中使用promtail+loki+grafna收集k8s日志并展示
Rancher中使用promtail+loki+grafna收集k8s日志并展示 根据应用需求和日志数量级别选择对应的日志收集、过滤和展示方式,当日志量不太大,又想简单集中管理查看日志时,可使用promtail+loki+grafna的方式。本文找那个loki和grafana外置在了k8s集群之外。 1、添加Chart Repo …...
modelbox线程爆满宕机bug
序 该bug的解决需要特别感谢张同学。有了大佬的帮助,这个bug才得以解决。 问题现象 modelbox可以进行模型推理,但压测一段时间后,modelbox会宕机,并发生段错误。 “libgomp: Thread creation failed: Resource temporarily una…...
KUKA机器人如何在程序中编辑等待时间?
KUKA机器人如何在程序中编辑等待时间? 如下图所示,如何实现在P1点和P2点之间等待设定的时间? 如下图所示,可以直接输入wait sec 2(等待2秒), 如下图所示,再次选中该程序后&#…...
MQ入门简介
当年入门MQ时跟着尚硅谷RabbitMQ视频学习所做的一些笔记,现在上传方便有需要小伙伴查看 一:MQ的相关概念 1.什么是MQ MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
图解JavaScript原型:原型链及其分析 | JavaScript图解
忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...
