Vue源碼學習之數據初始化

在這裏思考一個問題,使用 Vue的時候須要在建立Vue實例時傳入一個 option,這裏包含了咱們定義的 props、methods、data等。而在 methods的方法中獲取 data中的 key值都是直接經過 this.key獲取 option對象中的 methods中的定義的方法如何經過 this訪問到data中的數據呢?

let vue = new Vue({
    el: '#app',
    methods: {
      say() {
        console.log(this.msg)
      }
    },
    data: {
      msg: 'jjjjj'
    }
})
複製代碼

一開始我想是將datamethods中的數據全都掛載到了vm上,然而Vue實例上有methods中定義的方法,卻沒有data中的屬性,data中的數據所有存儲在vm._data中,經過this.key訪問實際上是this._data.key,Vue在這裏作了一層代理,經過defineProperty設置了vm的getter和setter,而methods中的方法在initMethods方法中將其中的this綁定到了vm上,這樣methods中方法訪問的this也就指向了_data。 
javascript

下面是參照源碼相關邏輯的簡化代碼:vue

function MyVue (option) {
  this._init(option)
}

MyVue.prototype._init = function (option) {
  const vm = this
  vm.$options = option // 源碼在此作了對子組件option的合併處理
  if (vm.$options.methods) initMethods(vm, vm.$options.methods) // 源碼中還有對props的處理,data、props、methods都會作查重處理,不能有相同的屬性名
  if (vm.$options.data) initData(vm)
}

function initMethods (vm, methods) {
  const props = vm.$options.props
  for (const key in methods) {
    vm[key] = methods[key].bind(vm) // 將methods上的方法掛載到vm上並將方法中全部的this指向vm,經過下面的proxy就能夠訪問到_data上的屬性
  }
}

function initData (vm) { // 將data上數據複製到_data並遍歷全部屬性添加代理
  vm._data = vm.$options.data
  const keys = Object.keys(vm._data)
  let i = keys.length
  while (i--) {
    const key = keys[i]
    proxy(vm, `_data`, key)
  }
}
function proxy (target, sourceKey, key) {
  let sharedPropertyDefinition = {}
  sharedPropertyDefinition.get = function proxyGetter () {
    return this[sourceKey][key]
  }
  sharedPropertyDefinition.set = function proxySetter (val) {
    this[sourceKey][key] = val
  }
  Object.defineProperty(target, key, sharedPropertyDefinition) // 一層代理,每次訪問this[key]時代理到this._data[key]
}

let app = new MyVue({
  methods: {
    say: function () {
      console.log(this.msg + this.age)
    }
  },
  data: {
    msg: 'jjj',
    age: 33
  }
})
app.say() // jjj33

複製代碼
相關文章
相關標籤/搜索