返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Vue2this直接获取data和methods原理解析
  • 263
分享到

Vue2this直接获取data和methods原理解析

Vue2this获取datamethodsVue2datamethods 2022-12-25 18:12:27 263人浏览 八月长安
摘要

目录学习目标如何学习调试 Vue2 源码分析源码调试initStateinitMethodsinitData总结学习目标 本篇文章将通过阅读 vue 的源码,来回答 [为什么 Vue

学习目标

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

仓库地址:GitHub

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

如何学习调试 vue2 源码

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

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

image.png

安装完依赖后执行命令:

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的资料请关注编程网其它相关文章!

--结束END--

本文标题: Vue2this直接获取data和methods原理解析

本文链接: https://lsjlt.com/news/175781.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作