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,自增ID
    vm._uid = uid++

    vm._isVue = true
    // merge options 合并options
    if (options && options._isComponent) {
     
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }

      vm._renderProxy = vm
   
    // expose real self
    vm._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)

    // 初始化provide
    initProvide(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 parent
  let parent = options.parent
  //当前组件存在父级并且当前组件不是抽象组件
  if (parent && !options.abstract) {
  //通过while循环来向上循环,如果当前组件的父级是抽象组件并且也存在父级,那就继续向上查找当前组件父级的父级
    while (parent.$options.abstract && parent.$parent) {
    //更新parent
      parent = parent.$parent
    }
    //把该实例自身添加进找到的父级的$children属性中
    parent.$children.push(vm)
  }
  //直到找到第一个不是抽象类型的父级时,将其赋值vm.$parent
  vm.$parent = parent
  //设置实例根元素。判断如果当前实例存在父级,那么当前实例的根实例$root属性就是其父级的根实例$root属性,如果不存在,那么根实例$root属性就是它自己
  vm.$root = parent ? parent.$root : vm

  vm.$children = []
  vm.$refs = {}

  vm._watcher = null
  vm._inactive = null
  vm._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 tree
  vm._staticTrees = null // v-once cached trees
  const options = vm.$options
  const parentVnode = vm.$vnode = options._parentVnode // the placeholder node in parent tree
  const 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.data

  defineReactive(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选项中的数据转化成键值对的形式赋给result
  const 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].from
      let 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].default
          result[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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C_11练习题答案

一、单项选择题(本大题共20小题,每小题2分,共40分。在每小题给出的四个备选项中,选出一个正确的答案,并将所选项前的字母填写在答题纸的相应位置上。) 以下叙述中正确的是(C)A.C语言不是一种高级语言 B.C语言不用编译就能被计算机执行 C.C语言能够直接访问物理地址和进行位…

计算机设计大赛信息可视化设计的获奖经验剖析解读—基于本专栏文章助力4C大赛【全网最全万字攻略-获奖必读】

文章目录 一.中国大学生计算机设计大赛1.1赛道解读1.2 信息可视化设计小类介绍1.2 小类区别解读 二.信息可视化设计赛道获奖经验2.1 四小类作品预览2.1.1 数据可视化小类-优秀参赛作品展览2.1.2 信息图形设计小类-优秀参赛作品展览2.1.3 动态信息影像&#xff08;MG动画&#x…

css3 clip-path剪切图片

大致看了一下&#xff0c;反正以后用到就慢慢调吧 剪切四个角 clip-path: polygon(14px 0, calc(100% - 14px) 0, 100% 14px, 100% calc(100% - 14px), calc(100% - 14px) 100%, 14px 100%, 0 calc(100% - 14px), 0 14px); 三角形 clip-path: polygon(50% 0,0 100%, 100% 100…

ShardingSphere数据分片之读写分离

1、概述 读写分离是一种常见的数据库架构&#xff0c;它将数据库分为主从库&#xff0c;一个主库&#xff08;Master&#xff09;用于写数据&#xff0c;多个从库&#xff08;Slave&#xff09;进行轮询读取数据的过程。主从库之间通过某种通讯机制进行数据的同步。 所以&…

【视觉SLAM十四讲学习笔记】第四讲——李代数求导与扰动模型

专栏系列文章如下&#xff1a; 【视觉SLAM十四讲学习笔记】第一讲——SLAM介绍 【视觉SLAM十四讲学习笔记】第二讲——初识SLAM 【视觉SLAM十四讲学习笔记】第三讲——旋转矩阵 【视觉SLAM十四讲学习笔记】第三讲——旋转向量和欧拉角 【视觉SLAM十四讲学习笔记】第三讲——四元…

《PCL多线程加速处理》-滤波-统计滤波

《PCL多线程加速处理》-滤波-统计滤波 一、效果展示二、实现方式三、代码一、效果展示 提升速度随着点云越多效果越明显 二、实现方式 1、原始的统计滤波实现方式 #include <pcl/filters/statistical_outlier_removal.h>pcl::PointCloud<pcl::PointXYZ

pr模板哪个网站好?免费Pr模板视频素材下载网站 Prmuban.com

pr模板哪个网站好&#xff1f;哪里可以下载免费的pr模板视频素材&#xff0c;PR模板网&#xff08;Prmuban.com&#xff09;影视后期制作模板视频剪辑素材资源网站。 包含PR模板、PR插件、PR预设、MOGRT、LUT、转场特效、音乐素材、音效素材等&#xff0c;更好的剪辑师必备资源…

【jmeter】接口测试流程

1、Jmeter简介 Jmeter是由Apache公司开发的一个纯Java的开源项目&#xff0c;即可以用于做接口测试也可以用于做性能测试。 Jmeter具备高移植性&#xff0c;可以实现跨平台运行。 Jmeter可以实现分布式负载。 Jmeter采用多线程&#xff0c;允许通过多个线程并发取样或通过独…

Windows中使用pthread线程库

由于时间成本&#xff0c;不想使用Windows线程API&#xff0c;因此想用pthread线程库&#xff1b;但pthread是Linux默认的POSIX线程库&#xff0c;Windows中并不自带&#xff0c;需要自己配置。 因为pthread遵循POSIX标准&#xff0c;因此其在Windows中使用应该和Linux中大同小…

UDP特性之广播

UDP特性之广播 1. 广播的特点2. 设置广播属性3. 广播通信流程4. 通信代码总结 1. 广播的特点 广播的UDP的特性之一&#xff0c;通过广播可以向子网中多台计算机发送消息&#xff0c;并且子网中所有的计算机都可以接收到发送方发送的消息&#xff0c;每个广播消息都包含一个特殊…

Clickhouse RoaringBitmap

https://blog.csdn.net/penriver/article/details/119736050 https://juejin.cn/post/7179956435806076988 BitMap适合连续密集的正整数存储&#xff0c;对于稀疏的正整数存储&#xff0c;其性能在很多时候是没办法和int数组相比的&#xff0c;尤其是正整数跨度较大的场景&…

外汇天眼:Coinbase国际交易所将启动现货市场

Coinbase宣布了Coinbase国际交易所扩张的下一阶段——退出符合条件客户的非美国现货市场。 这一最新发展旨在满足Coinbase全球用户群体的独特需求和需求&#xff0c;同时强化其扩大国际访问可信产品和服务的战略使命。 Coinbase国际交易所现货交易的推出和扩展将分阶段进行。1…

大数据/人工智能/EXCEL/R语言精品教材推荐

泰迪智能科技携手人民邮电出版社通过采用任务式、项目式等多种教材编写模式&#xff0c;教材内容注重实践能力培养&#xff0c;贴合教师教学实际和学生实践实验&#xff0c;已经被1500余所院校选用为教材。 图书优势 理实一体化 本系列教材注重学生的实践能力培养&#xff0…

TCP/UDP 协议

目录 一.TCP协议 1.介绍 2.报文格式 ​编辑 确认号 控制位 窗口大小 3.TCP特性 二.TCP协议的三次握手 1.tcp 三次握手的过程 三.四次挥手 2.有限状态机 四.tcp协议和udp协议的区别 五.udp协议 UDP特性 六.telnet协议 一.TCP协议 1.介绍 TCP&#xff08;Transm…

Sql标准梳理

SQL&#xff08;Structured Query Language&#xff09;是一种用于管理关系型数据库管理系统&#xff08;RDBMS&#xff09;的标准化语言。SQL标准由国际标准化组织&#xff08;ISO&#xff09;和美国国家标准化组织&#xff08;ANSI&#xff09;制定和维护&#xff0c;旨在提供…

安全护航:迅软DSE加密软件在设计院所图纸文件中的成功案例分享

近年来&#xff0c;随着信息化强国战略和可持续发展方针的推动&#xff0c;国内各大设计院所和建筑机构积极推进信息化建设&#xff0c;将电子文件作为主要的信息存储方式&#xff0c;并将其作为单位内外部信息交换的关键载体。在这一背景下&#xff0c;创新设计作为建筑设计单…

csrf和ssrf的区别,攻击如何防护

CSRF&#xff08;跨站请求伪造&#xff09;和SSRF&#xff08;服务器端请求伪造&#xff09;都是网络安全中的常见攻击类型&#xff0c;但它们的目标和攻击方式有所不同。理解这两种攻击的区别对于有效地防御它们至关重要。 CSRF和SSRF的主要区别在于攻击的发起者和目标。CSRF…

Crypto基础之密码学

FLAG&#xff1a;20岁的年纪不该困在爱与不爱里&#xff0c;对吗 专研方向: 密码学&#xff0c;Crypto 每日emo&#xff1a;今年你失去了什么&#xff1f; Crypto基础之密码学 前言一、编码Base编码base64&#xff1a;Base32 和 Base16&#xff1a;uuencode&#xff1a;xxencod…

GO并发编程综合应用

一.GO并发编程综合应用 1.生产者消费者模式 1.1需求分析 ​ 生产者每秒生产一个商品&#xff0c;并通过物流公司取货 ​ 物流公司将商品运输到商铺 ​ 消费者阻塞等待商铺到货&#xff0c;需要消费10次商品 1.2实现原理 1.3代码实现&#xff1a; package mainimport (&q…

chatGPT 国内版,嵌入midjourney AI创作工具

聊天GPT国内入口,免切网直达,可直接多语言对话,操作简单,无需复杂注册,智能高效,即刻使用.可以用作个人助理,学习助理,智能创作、新媒体文案创作、智能创作等各种应用场景! 地址&#xff1a; https://ai.wboat.cn/