Vue源码阅读之Vue构造函数(一)

前端技术日新月异,过一段时间就会涌现一些新的技术框架或者概念。并且目前使用最广泛的三大前端库,也不断地在更新版本增加新特性。对于前端开发人员来说,都有种学不动的无力感,还要面对来自“后浪”的挑战。因此提升技术的深度和广度,是塑造自我核心竞争力的关键一步。今天咋们就来阅读理解Vue的源码,知道我们平时在开发过程中经常使用的属性、生命周期以及数据双向绑定的实现机制。

一、项目结构

首先我们需要将Vue源码从github上拉倒本地,现在最新版本的Vue加入了typescript类型检测。我们都知道javascript是弱类型语言,书写代码的时候没有对变量的类型进行定义,后期扩展、团队开发中很容易犯错。大家还不了解typescript可以先看官方文档,不然源码中的语法看起来可能存在一定的阅读障碍。

项目中我们重点关注src下面的complier(编译相关)、core(核心代码逻辑)、platforms(平台相关)这三部分内容,基本涵盖了平常工程化开发中所用到的知识的底层原理。

二、定义Vue构造函数

core/instance/index.js中定义了Vue构造函数并暴露出去,属于原生javascript面向对象编程思想,结合工厂模式和原型链模式实现继承。

 在代码中我们会看到许多process变量,这个属于node.js中的对象,根据打包命令能判断环境变量区分开发环境、生产环境,继而走不同的代码逻辑。

Vue函数体中执行了_init方法,根据实例化vue传入的options不同生成不同的对象,_init方法在initMixin后进行了混入。

下面的几个mixin方法,就是在Vue对象的原型上混入公共方法,包括初始化、state数据、事件处理、生命周期、render。

三、_init方法

core/instance/init.js文件中我们看到_init方法定义在Vue.prototype原型上。函数体中排除process对于环境变量的判断,其实代码量不是很多。

 这部分代码判断vue实例是否是组件,不是组件就将传入的options在内部进行合并,保留vm对象的完整性。

 这部分就会初始化生命周期、事件、渲染页面、state数据。callHook方法用于调用组件内部相应的生命周期钩子,看到这里我们就很好理解为什么组件中created钩子是在页面数据初始化之后进行调用,并且inject数据在data/props之前就能获取到。

最后就是将vue实例$mount挂载到对应的dom节点上。

四、callHook函数

core/instance/lifecycle.js中看到callHook这个方法接受两个参数vm、hook,会获取options参数中传入的对应钩子的执行函数。然后通过invokeWithErrorHandling这个方法进行处理。

  invokeWithErrorHandling方法定义在core/util/error.js中,核心逻辑就是红框中标注的部分,在vm实例对象上通过apply、call进行调用执行。并且钩子函数本身就是promise,也会返回promise对象,可以通过catch进行错误捕获。

现在看来,生命周期中的钩子函数,相当于在组件进行特定操作后,比如:数据初始化、dom重绘、组件销毁等,Vue库内部提供的可以在自定义组件中进行副作用操作的钩子。至于数据更新如何改变虚拟dom,继而触发页面重绘的逻辑,都是在框架内部进行处理的。

五、initState初始化组件数据

core/instance/state.js中initState函数会初始化props、methods、data、computed、watch这一系列属性。我们重点看initData这个方法的逻辑、

 先是获取options上的data对象,判断是否是函数然后走不同的逻辑,并且将数据赋值给vm._data私有变量。

 接下来这段代码就很重要,有几个作用:

  1. hasOwn判断methods、props中是否有同名属性;
  2. props中如果没有同名的属性,isReserved方法判断变量名是否以“$”、"_"两个特俗字符开头,这两个属于特定字符适用于在类中定义私有属性;
  3. proxy方法通过Object.defineProperty(target, propKey, propDesc)方法将vm.optios.data上的数据做了一层代理。能直接在vm对象对象上进行set赋值、get取值操作;

 最后observe是new Observer(value)的实例,是基于Vue实现了观察者模式,监听数据变化,更新vNode重绘UI页面。这块比较晦涩难懂,研究透了可以单独进行讲解。

 我目前是通过定义Vue构造函数->_init()->initState()->initData()这一条线来阅读源码。诚然里面的知识点、细节很多,需要花时间钻研!

 最后上一张流程图:

原文地址:https://www.cnblogs.com/lodadssd/p/13738733.html