Vue2 this直接获取data和methods原理解析

 更新时间:2022年12月25日 15:20:22   作者:codeniu  
这篇文章主要为大家介绍了Vue2 this直接获取data和methods原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

学习目标

本篇文章将通过阅读 vue 的源码,来回答 [为什么 Vue2 this 能够直接获取到 data 和 methods?]

仓库地址:Github

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

如何学习调试 vue2 源码

通过去改源码的方式来学习代码,就是看到一段代码,你可能不是太懂它具体的作用是什么,那就尝试去改其中几行代码,猜测他们可能会造成那些影响,然后执行代码去验证你的猜想。

使用 Github Workspace 克隆一份代码,定位到源码位置,如下图:

安装完依赖后执行命令:

pnpm run dev

编译器会实时的将代码打包到 dist 目录下,如图:

我们引入打包后的代码,就可以实时的调试源码了,在example文件夹下新建一个html文件,并放入如下内容:

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>Document</title>
 </head>
 <body>
   <div id="app">
     <h2 @click="changeMsg">hello {{msg}}</h2>
   </div>
   <script src="../dist/vue.js"></script>
   <script>
     const vm = new Vue({
       el: '#app',
       data: {
         msg: 'world'
       },
       methods: {
         changeMsg() {
           this.msg = 'codeniu'
         }
       }
     })
   </script>
 </body>
</html>

使用 vscode 拓展 Live Server,打开文件:

Github Workspace 会生成一个在线预览的地址,所有的操作都是在浏览器中完成的,非常便捷。

使用浏览器的调试工具在 new Vue() 这行打上断点,开始调试:

分析源码

调试

我们在断点调试的时候要带着一下两个问题,看看vue实例化的步骤是什么:

  • data 中的数据为什么可以用 this 直接获取到
  • methods 中的方法为什么可以用 this 直接获取到

也就是关注data 与 methods 两个关键词,果不其然,在 mergeOptions 方法中发现了我们想要寻找的关键字。

找到源码中 mergeOptions 的位置:

export function initMixin(Vue: typeof Component) {
  Vue.prototype._init = function (options?: Record<string, any>) {
  ...
  
    // merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options as any)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor as any),
        options || {},
        vm
      )
    }
    
  ...
  }
}

initState

这一步操作是将所有选项合并,为下一步 initState 做准备,在 initState 处打上断点, F8 跳到这个断点处,F10 进入到这个函数内部。

export function initState(vm: Component) {
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)

  // Composition API
  initSetup(vm)

  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    const ob = observe((vm._data = {}))
    ob && ob.vmCount++
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

从代码上看这个函数的功能是进行一些初始化操作

  • initMethods 初始化 methods
  • initData 初始化 data
  • initComputed 初始化 computed

在 initMethods 与 initData 处分别打断点进入。

initMethods

function initMethods(vm: Component, methods: Object) {
  const props = vm.$options.props
  for (const key in methods) {
    if (__DEV__) {
      if (typeof methods[key] !== 'function') {
        warn(
          `Method "${key}" has type "${typeof methods[
            key
          ]}" in the component definition. ` +
            `Did you reference the function correctly?`,
          vm
        )
      }
      if (props && hasOwn(props, key)) {
        warn(`Method "${key}" has already been defined as a prop.`, vm)
      }
      if (key in vm && isReserved(key)) {
        warn(
          `Method "${key}" conflicts with an existing Vue instance method. ` +
            `Avoid defining component methods that start with _ or $.`
        )
      }
    }
    vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
  }
}

这个函数看起来像是用来初始化组件实例的方法的。它接收两个参数:vm 和 methods,其中 vm 是组件实例,methods 是包含组件方法的对象。

首先,这个函数检查组件是否定义了 props 属性。如果定义了,它会警告用户,如果方法名和已有的 prop 名称相同,给出警告。

然后检查函数名是否包含 $ 与 _ ,如果方法名包含这两个符号,给出警告。

最后使用bind函数将this指向为vm,因此我们才得以使用this访问到vm实例中的所有选项。

initData

function initData(vm: Component) {
  let data: any = vm.$options.data
  data = vm._data = isFunction(data) ? getData(data, vm) : data || {}
  if (!isPlainObject(data)) {
    data = {}
    __DEV__ &&
      warn(
        'data functions should return an object:\n' +
          'https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
        vm
      )
  }
  // proxy data on instance
  const keys = Object.keys(data)
  const props = vm.$options.props
  const methods = vm.$options.methods
  let i = keys.length
  while (i--) {
    const key = keys[i]
    if (__DEV__) {
      if (methods && hasOwn(methods, key)) {
        warn(`Method "${key}" has already been defined as a data property.`, vm)
      }
    }
    if (props && hasOwn(props, key)) {
      __DEV__ &&
        warn(
          `The data property "${key}" is already declared as a prop. ` +
            `Use prop default value instead.`,
          vm
        )
    } else if (!isReserved(key)) {
      proxy(vm, `_data`, key)
    }
  }
  // observe data
  const ob = observe(data)
  ob && ob.vmCount++
}

InitData 函数初始化 Vue.js 组件的数据:

  • 如果 data 属性是一个函数,则使用 Vue 实例作为参数调用它以获取数据。
  • 检查数据是否为普通对象。如果不是,则使用空对象作为数据,并给出警告。
  • 循环访问数据对象,使用 Object.defineProperty 设置对象的get与set函数,为下一步响应式做铺垫。
  • 使用观察函数观察数据。在数据发生改变时响应到页面,或者在页面发生变化时,响应到数据。

总结

通过本次课程的学习,加深了在浏览器中调试代码的方法,并且通过阅读源码对vue2的响应式原理有了进一步的了解。

以上就是Vue2 this直接获取data和methods原理解析的详细内容,更多关于Vue2 this获取data methods的资料请关注脚本之家其它相关文章!

相关文章

  • vue数据双向绑定原理解析(get & set)

    vue数据双向绑定原理解析(get & set)

    这篇文章主要为大家详细解析了vue.js数据双向绑定原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • 详解Vue3中Teleport的使用

    详解Vue3中Teleport的使用

    门户(Portal)的概念是Vue3的新功能之一,也就是将模板 HTML 移至 DOM 的不同部分的方法。Portal 是 React 中的常见功能,Vue2 的 portal-vue &nbsp;库也提供了相似的功能。在 Vue3 中用 Teleport 对这个概念提供了原生支持。本文将介绍Teleport的相关用法
    2021-05-05
  • vue中轮训器的使用

    vue中轮训器的使用

    今天小编就为大家分享一篇关于vue中轮训器的使用,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • Vue基础之侦听器详解

    Vue基础之侦听器详解

    这篇文章主要为大家介绍了Vue基础之侦听器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • vue+element下拉列表默认值问题

    vue+element下拉列表默认值问题

    这篇文章主要介绍了vue+element下拉列表默认值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • 写一个Vue loading 插件

    写一个Vue loading 插件

    这篇文章主要介绍了如何写一个Vue loading 插件,帮助大家更好的理解和学习vue 插件的相关知识,感兴趣的朋友可以了解下
    2020-11-11
  • vue解决跨域问题的几种常用方法(CORS)

    vue解决跨域问题的几种常用方法(CORS)

    在Vue中解决跨域问题有多种方法,今天通过本文给大家介绍几种比较常见的方法,对vue解决跨域问题感兴趣的朋友跟随小编一起看看吧
    2023-05-05
  • VueJS实现用户管理系统

    VueJS实现用户管理系统

    这篇文章主要为大家详细介绍了VueJS实现用户管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • Vue Router如何刷新当前页面

    Vue Router如何刷新当前页面

    Vue项目, 在实际工作中, 有些时候需要在 加载完某些数据之后对当前页面进行刷新, 这篇文章主要为大家介绍了三种常用方法,需要的可以参考一下
    2023-10-10
  • Vue渲染器如何对节点进行挂载和更新

    Vue渲染器如何对节点进行挂载和更新

    这篇文章主要介绍了Vue 的渲染器是如何对节点进行挂载和更新的,文中通过代码示例给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-05-05

最新评论