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()时,会经过以下几个步骤:

  1. 初始化Vue实例的配置:Vue会将我们传入的配置对象进行初始化,包括数据、计算属性、方法等。
  2. 初始化生命周期钩子函数:Vue会在初始化过程中执行一系列的生命周期钩子函数,例如beforeCreatecreatedbeforeMountmounted等。
  3. 初始化事件系统:Vue会为实例创建一个事件总线,用于处理事件的监听和触发。
  4. 解析模板:如果配置中指定了template选项,Vue会将模板解析成渲染函数,以便后续的渲染过程中使用。
  5. 初始化渲染:Vue会创建一个虚拟DOM,并将之前解析的渲染函数进行渲染,生成真实DOM,并将其挂载到页面上。
  6. 数据响应式处理: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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/222685.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker安装最新版SQL Server并还原备份的数据库

docker安装数据库 拉取微软官方最新版镜像 docker pull mcr.microsoft.com/mssql/server 拉去镜像并创建容器 docker run -e "ACCEPT_EULAY" -e "SA_PASSWORDsa_password_123456" -p 1433:1433 -v /opt/:/opt --name sqlserver -d mcr.microsoft.com/ms…

前端页面显示的时间格式为:2022-03-18T01:46:08.000+00:00 如何转换为:年-月-日,并根据当前时间判断为几天前

由于后端每条博文的发表时间是以“xxxx—xx—xxxx:xx:xx”的形式显示的&#xff0c; 现在要在前端改成“xxxx年xx月xx日”的形式。 并对10分钟内发表的显示“刚刚”&#xff0c;对24小时内发表的显示“小时前”。 超过24小时&#xff0c;小于48小时&#xff0c;显示“1天前”。…

生产实践:基于K8S的私有化部署解决方案

随着国内数字化转型的加速和国产化进程推动&#xff0c;软件系统的私有化部署已经成为非常热门的话题&#xff0c;因为私有化部署赋予了企业更大的灵活和控制权&#xff0c;使其可以根据自身需求和安全要求定制和管理软件系统。下面分享下我们的基于k8S私有化部署经验。 私有化…

Nginx 服务器安装及配置文件详解

1. 安装nginx 1.1 选择稳定版本 我们编译安装nginx来定制自己的模块&#xff0c;机器CentOS 6.2 x86_64。首先安装缺少的依赖包&#xff1a; # yum -y install gcc gcc-c make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel 这些软件包如果yum上没有的话…

VS2022配置C++ 20解决import std报错

C 20新特征支持用import std来导入std模块&#xff0c;如下&#xff1a; 配置时主要有两个步骤&#xff1a; &#xff08;1&#xff09;项目--属性--常规--C语言标准--预览 - 最新 C 工作草案中的功能 (/std:clatest) 注意选择ISO C20 标准 (/std:c20)也不能正常使用&#xf…

【PgSQL】导出表结构为EXCEL

详细SQL语句&#xff1a; C.relname ‘你的表名’ 直接输入表面即可 PgSQL 打印表结构语句 SELECT C.relname AS "表名",CAST(obj_description(C.oid, pg_class) AS VARCHAR) AS "表名描述",A.attname AS "字段名",CASE WHEN A.attnotnull f …

(C++)无重复字符的最长子串--滑动窗口

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://le…

Oracle存储过程打印输出错误信息、行号,快速排查

测试存储过程如下&#xff1a; create or replace procedure prc_test isp_1 varchar2(2); beginp_1 : lxw测试;exceptionwhen others thendbms_output.put_line(sqlcode); --Oracle内置变量&#xff0c;错误代码dbms_output.put_line(sqlerrm); --Oracle内置变量&#xff0c;…

【SpringBoot篇】基于布隆过滤器,缓存空值,解决缓存穿透问题 (商铺查询时可用)

文章目录 &#x1f354;什么是缓存穿透&#x1f384;解决办法⭐缓存空值处理&#x1f388;优点&#x1f388;缺点&#x1f38d;代码实现 ⭐布隆过滤器&#x1f38d;代码实现 &#x1f354;什么是缓存穿透 缓存穿透是指在使用缓存机制时&#xff0c;大量的请求无法从缓存中获取…

KylinV10 将项目上传至 Github

KylinV10 将项目上传至 Github 银河麒麟操作系统 V10 是在 Ubuntu 的基础上开发的&#xff0c;所以适用于 Ubuntu 的也适用于 KylinV10 一般上传至 GitHub&#xff0c;有两种方式&#xff0c;一种是 HTTPS&#xff0c;一种是 SSH&#xff0c;但是在 KylinV10 操作系统 HTTPS 的…

Android camera的metadata

一、实现 先看一下metadata内部是什么样子&#xff1a; 可以看出&#xff0c;metadata 内部是一块连续的内存空间。 其内存分布大致可概括为&#xff1a; 区域一 &#xff1a;存 camera_metadata_t 结构体定义&#xff0c;占用内存 96 Byte 区域二 &#xff1a;保留区&#x…

单机环境下一人一单

优惠券秒杀 添加优惠卷 店铺发布优惠券又分为平价券和特价券, 平价券可以任意购买而特价券需要秒杀抢购(限制数量和时间) tb_voucher(平价券): 优惠券的基本信息 tb_seckill_voucher(秒杀券): 有voucher_id字段表示具有优惠卷的基本信息,此外还有库存,开始抢购时间,结束抢购…

软考机考考试第一批经验分享

由于机考的特殊性&#xff0c;考试环境与传统笔试环境有所不同。下面是与考试环境相关的总结&#xff1a; 草稿纸&#xff1a;考场提供足够数量的草稿纸&#xff0c;每位考生都会分发一张白纸作为草稿纸。在草稿纸上需要写上准考证号。如果不够用&#xff0c;可以向监考老师再次…

Mac部署Odoo环境-Odoo本地环境部署

Odoo本地环境部署 安装Python安装Homebrew安装依赖brew install libxmlsec1 Python运行环境Pycharm示例配置 Mac部署Odoo环境-Odoo本地环境部署 安装Python 新机&#xff0c;若系统没有预装Python&#xff0c;则安装需要版本的Python 点击查询Python官网下载 安装Homebrew 一…

实验:BGP配置

1.实验目的&#xff1a; 本实验旨在掌握BGP协议的基本概念和配置方法&#xff0c;以及使用Packet Tracer模拟网络环境进行BGP配置的方法。 2.实验要求&#xff1a; 理解BGP协议的基本概念和原理&#xff1b;掌握BGP协议的配置方法&#xff1b;能够使用Packet Tracer模拟网络…

2019年第八届数学建模国际赛小美赛C题预测通过拥堵路段所需的时间解题全过程文档及程序

2019年第八届数学建模国际赛小美赛 C题 预测通过拥堵路段所需的时间 原题再现&#xff1a; 在导航软件中&#xff0c;行程时间的估计往往是一个重要的功能。现有的导航软件往往通过出租车或安装了该软件的车辆获取实时GPS数据来确定当前的路况。在交通拥堵严重的情况下&#…

【深度学习初探】Day32 - 三维点云数据基础

【深度学习初探】Day32 - 三维点云数据基础 文章目录 【深度学习初探】Day32 - 三维点云数据基础一、点云的定义二、点云的获取三、点云的属性四、点云的存储格式4.1 pts4.2 LAS4.3 PCD4.4 .xyz4.5 .pcap 五、三维点云的表示方法5.1 二维投影5.2 三维体素5.3 原始点云5.4 图 六…

Node.js创建一个简单的WebSocket接口,实现通信交互

Node.js创建一个简单的WebSocket接口&#xff0c;实现通信交互 一、为什么使用WebSocket&#xff1f; WebSocket&#xff0c;最大特点就是&#xff0c;服务器可以主动向客户端推送信息&#xff0c;客户端也可以主动向服务器发送信息&#xff0c;是真正的双向平等对话&#xf…

IIS + Axios 跨域设置

1、服务器端设置IIS &#xff08;web.config) 即可&#xff0c;不需要对django settings.py做配置&#xff08;python manage.py runserver 才需要settings.py配置跨域&#xff0c;IIS在iis上配&#xff09; 网站根目录的web.config中加上这段&#xff1a; <httpProtocol&…

基于开源的JAVA mongodb jdbc 驱动 使用教程

基于开源的JAVA mongodb jdbc 驱动 使用教程介绍 介绍 本文介绍一款开源的基于JAVA的 Mongodb JDBC 驱动使用教程 开源地址 https://gitee.com/bgong/jdbc-mongodb-driver功能价值 与mybaits融合&#xff1a;复用mybatis的功能特性&#xff0c;如:缓存,if动态判断标签等特…