欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2022年12月25日 15:20:22   作者:codeniu  
這篇文章主要為大家介紹了Vue2?this直接獲取data和methods原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

學(xué)習(xí)目標(biāo)

本篇文章將通過閱讀 vue 的源碼,來回答 [為什么 Vue2 this 能夠直接獲取到 data 和 methods?]

倉庫地址:Github

  • 如何學(xué)習(xí)調(diào)試 vue2 源碼
  • data 中的數(shù)據(jù)為什么可以用 this 直接獲取到
  • methods 中的方法為什么可以用 this 直接獲取到
  • 學(xué)習(xí)源碼中優(yōu)秀代碼和思想,投入到自己的項目中

如何學(xué)習(xí)調(diào)試 vue2 源碼

通過去改源碼的方式來學(xué)習(xí)代碼,就是看到一段代碼,你可能不是太懂它具體的作用是什么,那就嘗試去改其中幾行代碼,猜測他們可能會造成那些影響,然后執(zhí)行代碼去驗證你的猜想。

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

安裝完依賴后執(zhí)行命令:

pnpm run dev

編譯器會實時的將代碼打包到 dist 目錄下,如圖:

我們引入打包后的代碼,就可以實時的調(diào)試源碼了,在example文件夾下新建一個html文件,并放入如下內(nèi)容:

<!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 會生成一個在線預(yù)覽的地址,所有的操作都是在瀏覽器中完成的,非常便捷。

使用瀏覽器的調(diào)試工具在 new Vue() 這行打上斷點,開始調(diào)試:

分析源碼

調(diào)試

我們在斷點調(diào)試的時候要帶著一下兩個問題,看看vue實例化的步驟是什么:

  • data 中的數(shù)據(jù)為什么可以用 this 直接獲取到
  • methods 中的方法為什么可以用 this 直接獲取到

也就是關(guān)注data 與 methods 兩個關(guān)鍵詞,果不其然,在 mergeOptions 方法中發(fā)現(xiàn)了我們想要尋找的關(guān)鍵字。

找到源碼中 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 做準(zhǔn)備,在 initState 處打上斷點, F8 跳到這個斷點處,F(xiàn)10 進(jìn)入到這個函數(shù)內(nèi)部。

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)
  }
}

從代碼上看這個函數(shù)的功能是進(jìn)行一些初始化操作

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

在 initMethods 與 initData 處分別打斷點進(jìn)入。

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)
  }
}

這個函數(shù)看起來像是用來初始化組件實例的方法的。它接收兩個參數(shù):vm 和 methods,其中 vm 是組件實例,methods 是包含組件方法的對象。

首先,這個函數(shù)檢查組件是否定義了 props 屬性。如果定義了,它會警告用戶,如果方法名和已有的 prop 名稱相同,給出警告。

然后檢查函數(shù)名是否包含 $ 與 _ ,如果方法名包含這兩個符號,給出警告。

最后使用bind函數(shù)將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 函數(shù)初始化 Vue.js 組件的數(shù)據(jù):

  • 如果 data 屬性是一個函數(shù),則使用 Vue 實例作為參數(shù)調(diào)用它以獲取數(shù)據(jù)。
  • 檢查數(shù)據(jù)是否為普通對象。如果不是,則使用空對象作為數(shù)據(jù),并給出警告。
  • 循環(huán)訪問數(shù)據(jù)對象,使用 Object.defineProperty 設(shè)置對象的get與set函數(shù),為下一步響應(yīng)式做鋪墊。
  • 使用觀察函數(shù)觀察數(shù)據(jù)。在數(shù)據(jù)發(fā)生改變時響應(yīng)到頁面,或者在頁面發(fā)生變化時,響應(yīng)到數(shù)據(jù)。

總結(jié)

通過本次課程的學(xué)習(xí),加深了在瀏覽器中調(diào)試代碼的方法,并且通過閱讀源碼對vue2的響應(yīng)式原理有了進(jìn)一步的了解。

以上就是Vue2 this直接獲取data和methods原理解析的詳細(xì)內(nèi)容,更多關(guān)于Vue2 this獲取data methods的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論