likes
comments
collection
share

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

作者站长头像
站长
· 阅读数 12

前言

清单

  1. 如何学习调试 vue2 源码
  2. data 中的数据为什么可以用 this 直接获取到
  3. methods 中的方法为什么可以用 this 直接获取到
  4. 源码中哪些优秀代码和思想可以投入到自己的项目中

如何调试vue2源码

  • 先下载源代码 git clone https://github.com/vuejs/vue.git
  • 切换到2.6分支上,找到examples/todomvc/目录,就以todomvc为例子进行debugger调试

this为什么能够直接获取到data、methods中数据

先说总结:

methods中把所有方法都绑定到vue实例上,所以能通过this获取到实例上的方法

data中的所有数据都绑定给了vue实例中_data对象上,每次通过this.xxx拿数据的时候,其实是拿的this._data.xxx中的数据

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

  • 开始调试
  • examples/todomvc/index.html找到当前引入的app.js文件,这里是业务逻辑实现的地方
  • 在new Vue之前debugger一下
  • 在浏览器中刷新页面,进入浏览器断点模式

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

  • this._init(options)
  • 沿着断点调试,首先来到了_init初始化的地方
  • 接着进入该方法里面

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

  • Vue.prototype._init
  • 发现这是一个定义在Vue原型对象上的方法
  • 里面执行了以下事件
vm._self = vm;
initLifecycle(vm); // 初始化声明周期
initEvents(vm); // 初始化事件
initRender(vm); // 初始化渲染
callHook(vm, 'beforeCreate'); // 执行钩子函数
initInjections(vm); // 初始化  injections before data/props
initState(vm); // 初始化状态,这里开始处理data相关的
initProvide(vm); // 初始化注入 initProvide provide after data/props
callHook(vm, 'created'); // 执行钩子函数created

这里就是面试过程中常问问题,vue初始化过程中都发生了什么?以及声明周期的执行顺序和过程是什么?

  • 重点看initState()方法

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

  • 本次文章的主题就是为了探索data和methods的问题
  • 在该方法中重点看下initMethods和initData方法
  • 先看initMethods

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

  • methods中
  • vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm); 给vue实例vm添加绑定的方法,并把this指向指向vm
  • 如下图中看到的结果

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

  • 接下来看下initData方法

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

  • 该代码中重点是proxy(vm, "_data", key); 方法,给_data对象添加key,proxy方法具体实现如下图,所有的data中的数据都添加_data对象上,并从其上面拿数据;

【源码共读】第23期 | 为什么 Vue2 this 能够直接获取到 data 和 methods

  • 关于函数的默认配置
  • Object.defineProperty(target, key, sharedPropertyDefinition);
  • 直接在一个对象上定义一个新的属性,或者修改一个已经存在的属性
  • target:在哪个对象身上添加或者修改属性
  • key: 添加或修改的属性名
  • sharedPropertyDefinition:配置项,一般是一个对象

哪些思想可以用于自己项目

在_init方法中,那一排初始化函数调用中initxxxx(),最深的感受两点:

  • 一个好的函数命名的重要性,见名知意,省了好多烦恼
  • 每个函数都只做自己该做的事件,负责自己的职责,配合恰当的名字,让代码看起来简洁了很多

总结

  • 一般框架项目中都有可以调试的test example

  • 之前看vue2工具函数那一部分的时候,单看很多想不到应用场景,在调试代码的时候,发现封装的工具函数在好多地方都用到了

  • 亲自动手调试了vue框架的一部分代码,发现对框架原理和源码也不是那么害怕了

  • 之前觉得高深的东西,一旦开始行动了,困难也不是坚不可摧的😀