Vue 源碼閱讀(七) bind

起源

經過 Class 實現代碼

class Demo {
  constructor() {
    this.num = 1
    this.init()
  }

  resize() {
    alert(this.num)
  }

  init() {
    window.addEventListener('resize', this.resize)
  }
}

new Demo()

代碼執行後,縮放瀏覽器,此時彈窗顯示 undefinedvue

符合預期!!git

經過 Vue 實現的代碼

import Vue from 'vue'

new Vue({
  template: '<div></div>',
  data: {
    num: 1
  },
  methods: {
    resize() {
      alert(this.num)
    }
  },
  mounted() {
    window.addEventListener('resize', this.resize)
  }
}).$mount('#app')

縮放瀏覽器,此時彈框顯示 1github

不符合預期!!瀏覽器

代碼分析

按常理,綁定事件 this.resize 後,將會丟失 this 所指向的上下文,因此第一個代碼執行的結果是 undefinedapp

所以猜測,在 Vue 的實現版本中,綁定是必定不是定義在 methods 下的 resize 方法。oop

源碼分析

src/core/instance/state.js#L258源碼分析

function initMethods (vm: Component, methods: Object) {
  const props = vm.$options.props
  for (const key in methods) {
    // ...
    vm[key] = methods[key] == null ? noop : bind(methods[key], vm)
  }
}

能夠看到在 Vue 實例上綁定的方法,都是被 bind 處理過的。this

src/shared/util.js#L203prototype

function polyfillBind (fn: Function, ctx: Object): Function {
  function boundFn (a) {
    const l = arguments.length
    return l
      ? l > 1
        ? fn.apply(ctx, arguments)
        : fn.call(ctx, a)
      : fn.call(ctx)
  }

  boundFn._length = fn.length
  return boundFn
}

function nativeBind (fn: Function, ctx: Object): Function {
  return fn.bind(ctx)
}

export const bind = Function.prototype.bind
  ? nativeBind
  : polyfillBind

因而可知, Vue 的實例調用的方法,是通過 bind 後帶有上下文的新方法。code

相關文章
相關標籤/搜索